diff --git a/.gitignore b/.gitignore index 9269cefc51fa0..addc0e013545c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,8 @@ atlassian* /lib/internal/flex/varien/.settings /node_modules /.grunt +/Gruntfile.js +/package.json /pub/media/*.* !/pub/media/.htaccess @@ -49,3 +51,5 @@ atlassian* !/var/.htaccess /vendor/* !/vendor/.htaccess +/generated/* +!/generated/.htaccess diff --git a/.htaccess b/.htaccess index f3dbe217081ac..af9470488c632 100644 --- a/.htaccess +++ b/.htaccess @@ -32,6 +32,7 @@ DirectoryIndex index.php + ############################################ ## adjust memory limit @@ -53,7 +54,30 @@ ## disable user agent verification to not break multiple image upload php_flag suhosin.session.cryptua off + + +############################################ +## adjust memory limit + + php_value memory_limit 768M + php_value max_execution_time 18000 + +############################################ +## disable automatic session start +## before autoload was initialized + + php_flag session.auto_start off + +############################################ +## enable resulting html compression + + #php_flag zlib.output_compression on +########################################### +## disable user agent verification to not break multiple image upload + + php_flag suhosin.session.cryptua off + ########################################### ## disable POST processing to not break multiple image upload diff --git a/.php_cs b/.php_cs index 5bd1a01537611..4bd705bb09a2f 100644 --- a/.php_cs +++ b/.php_cs @@ -1,6 +1,6 @@ = 50600 && PHP_VERSION_ID < 50700 || PHP_VERSION_ID === 70002 || PHP_VERSION_ID === 70004 || PHP_VERSION_ID >= 70006)) { +if (!defined('PHP_VERSION_ID') || !(PHP_VERSION_ID >= 50605 && PHP_VERSION_ID < 50700 || PHP_VERSION_ID === 70002 || PHP_VERSION_ID === 70004 || PHP_VERSION_ID >= 70006)) { if (PHP_SAPI == 'cli') { - echo 'Magento supports PHP 5.6, 7.0.2, 7.0.4, and 7.0.6 or later. ' . + echo 'Magento supports PHP 5.6.5, 7.0.2, 7.0.4, and 7.0.6 or later. ' . 'Please read http://devdocs.magento.com/guides/v1.0/install-gde/system-requirements.html'; } else { echo << -

Magento supports PHP 5.6, 7.0.2, 7.0.4, and 7.0.6 or later. Please read +

Magento supports PHP 5.6.5, 7.0.2, 7.0.4, and 7.0.6 or later. Please read Magento System Requirements. @@ -35,6 +35,17 @@ $mask = file_exists($umaskFile) ? octdec(file_get_contents($umaskFile)) : 002; umask($mask); +if (empty($_SERVER['ENABLE_IIS_REWRITES']) || ($_SERVER['ENABLE_IIS_REWRITES'] != 1)) { + /* + * Unset headers used by IIS URL rewrites. + */ + unset($_SERVER['HTTP_X_REWRITE_URL']); + unset($_SERVER['HTTP_X_ORIGINAL_URL']); + unset($_SERVER['IIS_WasUrlRewritten']); + unset($_SERVER['UNENCODED_URL']); + unset($_SERVER['ORIG_PATH_INFO']); +} + if (!empty($_SERVER['MAGE_PROFILER']) && isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'text/html') !== false diff --git a/app/code/Magento/AdminNotification/Block/Grid/Renderer/Actions.php b/app/code/Magento/AdminNotification/Block/Grid/Renderer/Actions.php index 322c61b32a534..a7b11138628a4 100644 --- a/app/code/Magento/AdminNotification/Block/Grid/Renderer/Actions.php +++ b/app/code/Magento/AdminNotification/Block/Grid/Renderer/Actions.php @@ -2,7 +2,7 @@ /** * Adminhtml AdminNotification Severity Renderer * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/AdminNotification/Block/Grid/Renderer/Notice.php b/app/code/Magento/AdminNotification/Block/Grid/Renderer/Notice.php index b370cbd8b1a6f..aa95028cfb4a0 100644 --- a/app/code/Magento/AdminNotification/Block/Grid/Renderer/Notice.php +++ b/app/code/Magento/AdminNotification/Block/Grid/Renderer/Notice.php @@ -2,7 +2,7 @@ /** * Adminhtml AdminNotification Severity Renderer * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\AdminNotification\Block\Grid\Renderer; diff --git a/app/code/Magento/AdminNotification/Block/Grid/Renderer/Severity.php b/app/code/Magento/AdminNotification/Block/Grid/Renderer/Severity.php index 7d0ccd163b8e0..c348b6cc76101 100644 --- a/app/code/Magento/AdminNotification/Block/Grid/Renderer/Severity.php +++ b/app/code/Magento/AdminNotification/Block/Grid/Renderer/Severity.php @@ -2,7 +2,7 @@ /** * Adminhtml AdminNotification Severity Renderer * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\AdminNotification\Block\Grid\Renderer; diff --git a/app/code/Magento/AdminNotification/Block/Inbox.php b/app/code/Magento/AdminNotification/Block/Inbox.php index 899d141c9b07f..984de28fd4b94 100644 --- a/app/code/Magento/AdminNotification/Block/Inbox.php +++ b/app/code/Magento/AdminNotification/Block/Inbox.php @@ -2,7 +2,7 @@ /** * Adminhtml AdminNotification inbox grid * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\AdminNotification\Block; diff --git a/app/code/Magento/AdminNotification/Block/System/Messages.php b/app/code/Magento/AdminNotification/Block/System/Messages.php index 223941c6e43f7..db2ecf62f0685 100644 --- a/app/code/Magento/AdminNotification/Block/System/Messages.php +++ b/app/code/Magento/AdminNotification/Block/System/Messages.php @@ -1,6 +1,6 @@ collection = $messageCollectionFactory->create(); + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + } +} diff --git a/app/code/Magento/AdminNotification/composer.json b/app/code/Magento/AdminNotification/composer.json index 0a29908b77f6f..09d8ce41bbb03 100644 --- a/app/code/Magento/AdminNotification/composer.json +++ b/app/code/Magento/AdminNotification/composer.json @@ -2,11 +2,12 @@ "name": "magento/module-admin-notification", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/module-store": "100.2.*", "magento/module-backend": "100.2.*", "magento/module-media-storage": "100.2.*", "magento/framework": "100.2.*", + "magento/module-ui": "100.2.*", "lib-libxml": "*" }, "type": "magento2-module", diff --git a/app/code/Magento/AdminNotification/etc/acl.xml b/app/code/Magento/AdminNotification/etc/acl.xml index d18f5cf83406d..d37f71b32d0ed 100644 --- a/app/code/Magento/AdminNotification/etc/acl.xml +++ b/app/code/Magento/AdminNotification/etc/acl.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/adminhtml/di.xml b/app/code/Magento/AdminNotification/etc/adminhtml/di.xml index 8986ce73472e5..1be5f99616cc3 100644 --- a/app/code/Magento/AdminNotification/etc/adminhtml/di.xml +++ b/app/code/Magento/AdminNotification/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/adminhtml/events.xml b/app/code/Magento/AdminNotification/etc/adminhtml/events.xml index 07bd1ae5e8e92..9c897af0a2f94 100644 --- a/app/code/Magento/AdminNotification/etc/adminhtml/events.xml +++ b/app/code/Magento/AdminNotification/etc/adminhtml/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml b/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml index f64dcbdb51cfd..47c6644b9f369 100644 --- a/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml +++ b/app/code/Magento/AdminNotification/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/adminhtml/routes.xml b/app/code/Magento/AdminNotification/etc/adminhtml/routes.xml index 9ca1f2d4cd1ae..a710049993270 100644 --- a/app/code/Magento/AdminNotification/etc/adminhtml/routes.xml +++ b/app/code/Magento/AdminNotification/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/adminhtml/system.xml b/app/code/Magento/AdminNotification/etc/adminhtml/system.xml index 8038b914fd65b..ab0cff5f897c1 100644 --- a/app/code/Magento/AdminNotification/etc/adminhtml/system.xml +++ b/app/code/Magento/AdminNotification/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/config.xml b/app/code/Magento/AdminNotification/etc/config.xml index f1a1abb44546b..c088f7b5e11a7 100644 --- a/app/code/Magento/AdminNotification/etc/config.xml +++ b/app/code/Magento/AdminNotification/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/di.xml b/app/code/Magento/AdminNotification/etc/di.xml index a5f94685ed9d1..03e415dd3714e 100644 --- a/app/code/Magento/AdminNotification/etc/di.xml +++ b/app/code/Magento/AdminNotification/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/etc/module.xml b/app/code/Magento/AdminNotification/etc/module.xml index 77d9d4877ac0b..8fdfc713293d3 100644 --- a/app/code/Magento/AdminNotification/etc/module.xml +++ b/app/code/Magento/AdminNotification/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/registration.php b/app/code/Magento/AdminNotification/registration.php index ab3e6a6170db0..9bd6a540462f7 100644 --- a/app/code/Magento/AdminNotification/registration.php +++ b/app/code/Magento/AdminNotification/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_index.xml b/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_index.xml index 1d3650fa2afcb..1083e32f3c942 100644 --- a/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_index.xml +++ b/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml b/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml index e3d32f17b6356..4ac9f806e8c66 100644 --- a/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml +++ b/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml @@ -1,18 +1,14 @@ - + getNoticeMessageText(); ?>
getReadDetailsText(); ?> - \ No newline at end of file + diff --git a/app/code/Magento/AdminNotification/view/adminhtml/templates/system/messages.phtml b/app/code/Magento/AdminNotification/view/adminhtml/templates/system/messages.phtml index cd4a9a88ebe0c..a70a5e97b57c3 100644 --- a/app/code/Magento/AdminNotification/view/adminhtml/templates/system/messages.phtml +++ b/app/code/Magento/AdminNotification/view/adminhtml/templates/system/messages.phtml @@ -1,6 +1,6 @@ + +

+ + + notification_area.notification_area_data_source + notification_area.notification_area_data_source + + columns + + + + Magento\AdminNotification\Ui\Component\DataProvider\DataProvider + notification_area_data_source + identity + identity + + + Magento_Ui/js/grid/provider + + + identity + + + + + + + + + Magento_AdminNotification/js/grid/listing + Magento_AdminNotification/grid/listing + + + + + + Magento_AdminNotification/js/grid/columns/message + + text + asc + 30 + + + + + diff --git a/app/code/Magento/AdminNotification/view/adminhtml/web/js/grid/columns/message.js b/app/code/Magento/AdminNotification/view/adminhtml/web/js/grid/columns/message.js new file mode 100644 index 0000000000000..aedf996278834 --- /dev/null +++ b/app/code/Magento/AdminNotification/view/adminhtml/web/js/grid/columns/message.js @@ -0,0 +1,46 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'Magento_Ui/js/grid/columns/column', + 'underscore' +], function (Column, _) { + 'use strict'; + + return Column.extend({ + defaults: { + bodyTmpl: 'Magento_AdminNotification/grid/cells/message', + messageIndex: 'text', + fieldClass: { + message: true, + 'message-warning': false, + 'message-progress': false, + 'message-success': false, + 'message-error': false + }, + statusMap: { + 0: 'info', + 1: 'progress', + 2: 'success', + 3: 'error' + } + }, + + /** @inheritdoc */ + getLabel: function (record) { + return record[this.messageIndex]; + }, + + /** @inheritdoc */ + getFieldClass: function ($row) { + var status = this.statusMap[$row.status] || 'warning', + result = {}; + + result['message-' + status] = true; + result = _.extend({}, this.fieldClass, result); + + return result; + } + }); +}); diff --git a/app/code/Magento/AdminNotification/view/adminhtml/web/js/grid/listing.js b/app/code/Magento/AdminNotification/view/adminhtml/web/js/grid/listing.js new file mode 100644 index 0000000000000..ae17af57fbef4 --- /dev/null +++ b/app/code/Magento/AdminNotification/view/adminhtml/web/js/grid/listing.js @@ -0,0 +1,63 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/grid/listing', + 'Magento_Ui/js/lib/spinner', + 'jquery' +], function (Listing, loader, $) { + 'use strict'; + + return Listing.extend({ + defaults: { + imports: { + totalRecords: '${ $.provider }:data.totalRecords' + }, + selectors: { + collapsible: '.message-system-collapsible', + messages: '.message-system' + } + }, + + /** @inheritdoc */ + initObservable: function () { + this._super() + .track({ + totalRecords: 0 + }); + + return this; + }, + + /** @inheritdoc */ + showLoader: function () { + if (!this.source.firstLoad) { + this.fixLoaderHeight(); + this._super(); + } + }, + + /** + * Calculates loader height + * + * @param {Boolean} [closed] + */ + fixLoaderHeight: function (closed) { + var $messagesBlock = $(this.selectors.messages), + $collapsibleBlock = $(this.selectors.collapsible), + resultHeight = 0; + + if ($messagesBlock.length) { + resultHeight += $messagesBlock.outerHeight(); + } + + if ($collapsibleBlock.length && $collapsibleBlock.is(':visible') && !closed) { + resultHeight += $collapsibleBlock.outerHeight(); + } + + loader.get(this.name).height(resultHeight); + } + }); +}); diff --git a/app/code/Magento/AdminNotification/view/adminhtml/web/system/notification.js b/app/code/Magento/AdminNotification/view/adminhtml/web/system/notification.js index e3d170ef09c57..b905322545998 100644 --- a/app/code/Magento/AdminNotification/view/adminhtml/web/system/notification.js +++ b/app/code/Magento/AdminNotification/view/adminhtml/web/system/notification.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/AdminNotification/view/adminhtml/web/template/grid/cells/message.html b/app/code/Magento/AdminNotification/view/adminhtml/web/template/grid/cells/message.html new file mode 100644 index 0000000000000..b6f659885e864 --- /dev/null +++ b/app/code/Magento/AdminNotification/view/adminhtml/web/template/grid/cells/message.html @@ -0,0 +1,8 @@ + +
diff --git a/app/code/Magento/AdminNotification/view/adminhtml/web/template/grid/listing.html b/app/code/Magento/AdminNotification/view/adminhtml/web/template/grid/listing.html new file mode 100644 index 0000000000000..bce380af785a4 --- /dev/null +++ b/app/code/Magento/AdminNotification/view/adminhtml/web/template/grid/listing.html @@ -0,0 +1,32 @@ + +
+
+
+ +
+ + + +
+
+
+
    +
  • + + + +
  • +
+
+
+
diff --git a/app/code/Magento/AdminNotification/view/adminhtml/web/toolbar_entry.js b/app/code/Magento/AdminNotification/view/adminhtml/web/toolbar_entry.js index 2d69f616f029a..705d4005acc37 100644 --- a/app/code/Magento/AdminNotification/view/adminhtml/web/toolbar_entry.js +++ b/app/code/Magento/AdminNotification/view/adminhtml/web/toolbar_entry.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -98,4 +98,4 @@ define([ $('.notifications-action .notifications-counter').show(); } -}); \ No newline at end of file +}); diff --git a/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php b/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php index ccbef52b5a818..d35a409b58b98 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php +++ b/app/code/Magento/AdvancedPricingImportExport/Controller/Adminhtml/Export/GetFilter.php @@ -1,6 +1,6 @@ '', ImportAdvancedPricing::COL_TIER_PRICE_QTY => '', ImportAdvancedPricing::COL_TIER_PRICE => '', + ImportAdvancedPricing::COL_TIER_PRICE_TYPE => '' ]; /** @@ -279,6 +280,8 @@ protected function getExportData() } /** + * Correct export data. + * * @param array $exportData * @return array * @SuppressWarnings(PHPMD.UnusedLocalVariable) @@ -302,6 +305,12 @@ protected function correctExportData($exportData) : null ); unset($exportRow[ImportAdvancedPricing::VALUE_ALL_GROUPS]); + } elseif ($keyTemplate === ImportAdvancedPricing::COL_TIER_PRICE) { + $exportRow[$keyTemplate] = $row[ImportAdvancedPricing::COL_TIER_PRICE_PERCENTAGE_VALUE] + ? $row[ImportAdvancedPricing::COL_TIER_PRICE_PERCENTAGE_VALUE] + : $row[ImportAdvancedPricing::COL_TIER_PRICE]; + $exportRow[ImportAdvancedPricing::COL_TIER_PRICE_TYPE] + = $this->tierPriceTypeValue($row[ImportAdvancedPricing::COL_TIER_PRICE_PERCENTAGE_VALUE]); } else { $exportRow[$keyTemplate] = $row[$keyTemplate]; } @@ -311,11 +320,25 @@ protected function correctExportData($exportData) $customExportData[$key] = $exportRow; unset($exportRow); } + return $customExportData; } /** - * Get Tier and Group Pricing + * Check type for tier price. + * + * @param string $tierPricePercentage + * @return string + */ + private function tierPriceTypeValue($tierPricePercentage) + { + return $tierPricePercentage + ? ImportAdvancedPricing::TIER_PRICE_TYPE_PERCENT + : ImportAdvancedPricing::TIER_PRICE_TYPE_FIXED; + } + + /** + * Get tier prices. * * @param array $listSku * @param string $table @@ -336,6 +359,7 @@ protected function getTierPrices(array $listSku, $table) ImportAdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => 'ap.customer_group_id', ImportAdvancedPricing::COL_TIER_PRICE_QTY => 'ap.qty', ImportAdvancedPricing::COL_TIER_PRICE => 'ap.value', + ImportAdvancedPricing::COL_TIER_PRICE_PERCENTAGE_VALUE => 'ap.percentage_value', ]; if (isset($exportFilter) && !empty($exportFilter)) { $price = $exportFilter['tier_price']; @@ -371,6 +395,9 @@ protected function getTierPrices(array $listSku, $table) if (isset($price[1]) && !empty($price[1])) { $select->where('ap.value <= ?', $price[1]); } + if (isset($price[0]) && !empty($price[0]) || isset($price[1]) && !empty($price[1])) { + $select->orWhere('ap.percentage_value IS NOT NULL'); + } if (isset($updatedAtFrom) && !empty($updatedAtFrom)) { $select->where('cpe.updated_at >= ?', $updatedAtFrom); } diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php index d751fdc75882d..0bb44c238c720 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php @@ -1,6 +1,6 @@ 'Tier Price data price or quantity value is invalid', ValidatorInterface::ERROR_INVALID_TIER_PRICE_SITE => 'Tier Price data website is invalid', ValidatorInterface::ERROR_INVALID_TIER_PRICE_GROUP => 'Tier Price customer group is invalid', + ValidatorInterface::ERROR_INVALID_TIER_PRICE_TYPE => 'Value for \'tier_price_value_type\' ' . + 'attribute contains incorrect value, acceptable values are Fixed, Discount', ValidatorInterface::ERROR_TIER_DATA_INCOMPLETE => 'Tier Price data is incomplete', ValidatorInterface::ERROR_INVALID_ATTRIBUTE_DECIMAL => 'Value for \'%s\' attribute contains incorrect value, acceptable values are in decimal format', @@ -70,7 +80,7 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract protected $needColumnCheck = true; /** - * Valid column names + * Valid column names. * * @array */ @@ -80,6 +90,7 @@ class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\Abstract self::COL_TIER_PRICE_CUSTOMER_GROUP, self::COL_TIER_PRICE_QTY, self::COL_TIER_PRICE, + self::COL_TIER_PRICE_TYPE ]; /** @@ -379,7 +390,10 @@ protected function saveAndReplaceAdvancedPrices() $rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] ), 'qty' => $rowData[self::COL_TIER_PRICE_QTY], - 'value' => $rowData[self::COL_TIER_PRICE], + 'value' => $rowData[self::COL_TIER_PRICE_TYPE] === self::TIER_PRICE_TYPE_FIXED + ? $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]) ]; } @@ -429,7 +443,7 @@ protected function saveProductPrices(array $priceData, $table) } } if ($priceIn) { - $this->_connection->insertOnDuplicate($tableName, $priceIn, ['value']); + $this->_connection->insertOnDuplicate($tableName, $priceIn, ['value', 'percentage_value']); } } return $this; @@ -542,19 +556,24 @@ protected function retrieveOldSkus() */ protected function processCountExistingPrices($prices, $table) { + $oldSkus = $this->retrieveOldSkus(); + $existProductIds = array_intersect_key($oldSkus, $prices); + if (!count($existProductIds)) { + return $this; + } + $tableName = $this->_resourceFactory->create()->getTable($table); $productEntityLinkField = $this->getProductEntityLinkField(); $existingPrices = $this->_connection->fetchAssoc( $this->_connection->select()->from( $tableName, ['value_id', $productEntityLinkField, 'all_groups', 'customer_group_id'] - ) + )->where($productEntityLinkField . ' IN (?)', $existProductIds) ); - $oldSkus = $this->retrieveOldSkus(); foreach ($existingPrices as $existingPrice) { - foreach ($oldSkus as $sku => $productId) { - if ($existingPrice[$productEntityLinkField] == $productId && isset($prices[$sku])) { - $this->incrementCounterUpdated($prices[$sku], $existingPrice); + foreach ($prices as $sku => $skuPrices) { + if (isset($oldSkus[$sku]) && $existingPrice[$productEntityLinkField] == $oldSkus[$sku]) { + $this->incrementCounterUpdated($skuPrices, $existingPrice); } } } diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php index 051628e7e4a92..ffc191ac655f7 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php @@ -1,6 +1,6 @@ hasEmptyColumns($value) ) { $this->_addMessages([self::ERROR_TIER_DATA_INCOMPLETE]); diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPriceType.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPriceType.php new file mode 100644 index 0000000000000..d00d36b0eda27 --- /dev/null +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/TierPriceType.php @@ -0,0 +1,48 @@ +_addMessages([RowValidatorInterface::ERROR_INVALID_TIER_PRICE_TYPE]); + $isValid = false; + } + + return $isValid; + } +} diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php index 150555709b8b7..bc57b8482963a 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator/Website.php @@ -1,6 +1,6 @@ tierPriceType = $objectManager->getObject( + AdvancedPricing\Validator\TierPriceType::class, + [] + ); + } + + /** + * Test for isValid() method. + * + * @dataProvider isValidDataProvider + * @param array $value + * @param bool $expectedResult + */ + public function testIsValid(array $value, $expectedResult) + { + $result = $this->tierPriceType->isValid($value); + $this->assertEquals($expectedResult, $result); + } + + /** + * Data Provider for testIsValid(). + * + * @return array + */ + public function isValidDataProvider() + { + return [ + [ + [AdvancedPricing::COL_TIER_PRICE_TYPE => AdvancedPricing::TIER_PRICE_TYPE_FIXED], + true + ], + [ + [AdvancedPricing::COL_TIER_PRICE_TYPE => AdvancedPricing::TIER_PRICE_TYPE_PERCENT], + true + ], + [ + [], + true + ], + [ + [AdvancedPricing::COL_TIER_PRICE_TYPE => null], + true + ], + [ + [AdvancedPricing::COL_TIER_PRICE_TYPE => 'wrong type'], + false + ] + ]; + } +} 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 ad67ee5cc556a..6a0fd28ac7466 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 @@ -1,6 +1,6 @@ advancedPricing + $skuProduct = 'product1'; + $sku = $data[0][AdvancedPricing::COL_SKU]; + $advancedPricing = $this->getAdvancedPricingMock( + [ + 'retrieveOldSkus', + 'validateRow', + 'addRowError', + 'getCustomerGroupId', + 'getWebSiteId', + 'deleteProductTierPrices', + 'getBehavior', + 'saveAndReplaceAdvancedPrices', + 'processCountExistingPrices', + 'processCountNewPrices' + ] + ); + $advancedPricing ->expects($this->any()) ->method('getBehavior') ->willReturn(\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND); $this->dataSourceModel->expects($this->at(0))->method('getNextBunch')->willReturn($data); - $this->advancedPricing->expects($this->any())->method('validateRow')->willReturn(true); + $advancedPricing->expects($this->any())->method('validateRow')->willReturn(true); - $this->advancedPricing->expects($this->any())->method('getCustomerGroupId')->willReturnMap( + $advancedPricing->expects($this->any())->method('getCustomerGroupId')->willReturnMap( [ [$data[0][AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP], $tierCustomerGroupId], ] ); - $this->advancedPricing->expects($this->any())->method('getWebSiteId')->willReturnMap( + $advancedPricing->expects($this->any())->method('getWebSiteId')->willReturnMap( [ [$data[0][AdvancedPricing::COL_TIER_PRICE_WEBSITE], $tierWebsiteId], ] ); - $this->advancedPricing->expects($this->any())->method('saveProductPrices')->will($this->returnSelf()); + $oldSkus = [$sku => $skuProduct]; + $expectedTierPrices[$sku][0][self::LINK_FIELD] = $skuProduct; + $advancedPricing->expects($this->once())->method('retrieveOldSkus')->willReturn($oldSkus); + $this->connection->expects($this->once()) + ->method('insertOnDuplicate') + ->with(self::TABLE_NAME, $expectedTierPrices[$sku], ['value', 'percentage_value']); - $this->advancedPricing->expects($this->any())->method('processCountExistingPrices')->willReturnSelf(); - $this->advancedPricing->expects($this->any())->method('processCountNewPrices')->willReturnSelf(); + $advancedPricing->expects($this->any())->method('processCountExistingPrices')->willReturnSelf(); + $advancedPricing->expects($this->any())->method('processCountNewPrices')->willReturnSelf(); - $result = $this->invokeMethod($this->advancedPricing, 'saveAndReplaceAdvancedPrices'); + $result = $this->invokeMethod($advancedPricing, 'saveAndReplaceAdvancedPrices'); - $this->assertEquals($this->advancedPricing, $result); + $this->assertEquals($advancedPricing, $result); + } + + /** + * Test method saveAndReplaceAdvancedPrices with append import behaviour. + */ + public function testSaveAndReplaceAdvancedPricesAppendBehaviourDataAndCallsWithoutTierPrice() + { + $data = [ + 0 => [ + AdvancedPricing::COL_SKU => 'sku value', + AdvancedPricing::COL_TIER_PRICE_WEBSITE => null, + AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => 'tier price customer group value - not all groups', + AdvancedPricing::COL_TIER_PRICE_QTY => 'tier price qty value', + AdvancedPricing::COL_TIER_PRICE => 'tier price value', + AdvancedPricing::COL_TIER_PRICE_TYPE => AdvancedPricing::TIER_PRICE_TYPE_FIXED + ], + ]; + $tierCustomerGroupId = 'tier customer group id value'; + $tierWebsiteId = 'tier website id value'; + $expectedTierPrices = []; + + $skuProduct = 'product1'; + $sku = $data[0][AdvancedPricing::COL_SKU]; + $advancedPricing = $this->getAdvancedPricingMock( + [ + 'retrieveOldSkus', + 'validateRow', + 'addRowError', + 'getCustomerGroupId', + 'getWebSiteId', + 'deleteProductTierPrices', + 'getBehavior', + 'saveAndReplaceAdvancedPrices', + 'processCountExistingPrices', + 'processCountNewPrices' + ] + ); + $advancedPricing + ->expects($this->any()) + ->method('getBehavior') + ->willReturn(\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND); + $this->dataSourceModel->expects($this->at(0))->method('getNextBunch')->willReturn($data); + $advancedPricing->expects($this->any())->method('validateRow')->willReturn(true); + + $advancedPricing->expects($this->any())->method('getCustomerGroupId')->willReturnMap( + [ + [$data[0][AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP], $tierCustomerGroupId], + ] + ); + + $advancedPricing->expects($this->any())->method('getWebSiteId')->willReturnMap( + [ + [$data[0][AdvancedPricing::COL_TIER_PRICE_WEBSITE], $tierWebsiteId], + ] + ); + + $oldSkus = [$sku => $skuProduct]; + $expectedTierPrices[$sku][0][self::LINK_FIELD] = $skuProduct; + $advancedPricing->expects($this->never())->method('retrieveOldSkus')->willReturn($oldSkus); + $this->connection->expects($this->never()) + ->method('insertOnDuplicate') + ->with(self::TABLE_NAME, $expectedTierPrices[$sku], ['value', 'percentage_value']); + + $advancedPricing->expects($this->any())->method('processCountExistingPrices')->willReturnSelf(); + $advancedPricing->expects($this->any())->method('processCountNewPrices')->willReturnSelf(); + + $result = $this->invokeMethod($advancedPricing, 'saveAndReplaceAdvancedPrices'); + + $this->assertEquals($advancedPricing, $result); } /** @@ -575,6 +665,7 @@ public function saveAndReplaceAdvancedPricesAppendBehaviourDataProvider() AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => 'tier price customer group value - not all groups ', AdvancedPricing::COL_TIER_PRICE_QTY => 'tier price qty value', AdvancedPricing::COL_TIER_PRICE => 'tier price value', + AdvancedPricing::COL_TIER_PRICE_TYPE => AdvancedPricing::TIER_PRICE_TYPE_FIXED ], ], '$tierCustomerGroupId' => 'tier customer group id value', @@ -585,25 +676,25 @@ public function saveAndReplaceAdvancedPricesAppendBehaviourDataProvider() 'sku value' => [ [ 'all_groups' => false, - //$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS 'customer_group_id' => 'tier customer group id value', - //$tierCustomerGroupId 'qty' => 'tier price qty value', 'value' => 'tier price value', 'website_id' => 'tier website id value', + 'percentage_value' => null ], ], ], ], - [// tier customer group is equal to all group + [ '$data' => [ 0 => [ AdvancedPricing::COL_SKU => 'sku value', //tier AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier price website value', - AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => AdvancedPricing::VALUE_ALL_GROUPS, + AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => 'tier price customer group value - not all groups ', AdvancedPricing::COL_TIER_PRICE_QTY => 'tier price qty value', AdvancedPricing::COL_TIER_PRICE => 'tier price value', + AdvancedPricing::COL_TIER_PRICE_TYPE => AdvancedPricing::TIER_PRICE_TYPE_PERCENT ], ], '$tierCustomerGroupId' => 'tier customer group id value', @@ -613,33 +704,44 @@ public function saveAndReplaceAdvancedPricesAppendBehaviourDataProvider() '$expectedTierPrices' => [ 'sku value' => [ [ - 'all_groups' => true, - //$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS + 'all_groups' => false, 'customer_group_id' => 'tier customer group id value', - //$tierCustomerGroupId 'qty' => 'tier price qty value', - 'value' => 'tier price value', + 'value' => 0, + 'percentage_value' => 'tier price value', 'website_id' => 'tier website id value', ], ], ], ], - [ + [// tier customer group is equal to all group '$data' => [ 0 => [ AdvancedPricing::COL_SKU => 'sku value', //tier - AdvancedPricing::COL_TIER_PRICE_WEBSITE => null, - AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => 'tier price customer group value - not all groups', + AdvancedPricing::COL_TIER_PRICE_WEBSITE => 'tier price website value', + AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => AdvancedPricing::VALUE_ALL_GROUPS, AdvancedPricing::COL_TIER_PRICE_QTY => 'tier price qty value', AdvancedPricing::COL_TIER_PRICE => 'tier price value', + AdvancedPricing::COL_TIER_PRICE_TYPE => AdvancedPricing::TIER_PRICE_TYPE_FIXED ], ], '$tierCustomerGroupId' => 'tier customer group id value', '$groupCustomerGroupId' => 'group customer group id value', '$tierWebsiteId' => 'tier website id value', '$groupWebsiteId' => 'group website id value', - '$expectedTierPrices' => [], + '$expectedTierPrices' => [ + 'sku value' => [ + [ + 'all_groups' => true, + 'customer_group_id' => 'tier customer group id value', + 'qty' => 'tier price qty value', + 'value' => 'tier price value', + 'website_id' => 'tier website id value', + 'percentage_value' => null + ], + ], + ], ], [ '$data' => [ @@ -650,6 +752,7 @@ public function saveAndReplaceAdvancedPricesAppendBehaviourDataProvider() AdvancedPricing::COL_TIER_PRICE_CUSTOMER_GROUP => 'tier price customer group value - not all groups', AdvancedPricing::COL_TIER_PRICE_QTY => 'tier price qty value', AdvancedPricing::COL_TIER_PRICE => 'tier price value', + AdvancedPricing::COL_TIER_PRICE_TYPE => AdvancedPricing::TIER_PRICE_TYPE_FIXED ], ], '$tierCustomerGroupId' => 'tier customer group id value', @@ -660,12 +763,11 @@ public function saveAndReplaceAdvancedPricesAppendBehaviourDataProvider() 'sku value' => [ [ 'all_groups' => false, - //$rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS 'customer_group_id' => 'tier customer group id value', - //$tierCustomerGroupId 'qty' => 'tier price qty value', 'value' => 'tier price value', 'website_id' => 'tier website id value', + 'percentage_value' => null ], ] ], @@ -746,7 +848,7 @@ public function testSaveProductPrices($priceData, $oldSkus, $priceIn, $callNum) $this->connection->expects($this->exactly($callNum)) ->method('insertOnDuplicate') - ->with(self::TABLE_NAME, $priceIn, ['value']); + ->with(self::TABLE_NAME, $priceIn, ['value', 'percentage_value']); $this->invokeMethod($this->advancedPricing, 'saveProductPrices', [$priceData, 'table']); } diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Indexer/Product/Price/Plugin/ImportTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Indexer/Product/Price/Plugin/ImportTest.php index d65271d9ace54..67f6d33a9df15 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Indexer/Product/Price/Plugin/ImportTest.php +++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Indexer/Product/Price/Plugin/ImportTest.php @@ -1,6 +1,6 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/AdvancedPricingImportExport/etc/di.xml b/app/code/Magento/AdvancedPricingImportExport/etc/di.xml index c3444069c14c0..950054ab52412 100644 --- a/app/code/Magento/AdvancedPricingImportExport/etc/di.xml +++ b/app/code/Magento/AdvancedPricingImportExport/etc/di.xml @@ -1,7 +1,7 @@ @@ -14,6 +14,7 @@ Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\TierPrice Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\Website + Magento\AdvancedPricingImportExport\Model\Import\AdvancedPricing\Validator\TierPriceType diff --git a/app/code/Magento/AdvancedPricingImportExport/etc/export.xml b/app/code/Magento/AdvancedPricingImportExport/etc/export.xml index f04e399fdfedb..da176e7bd73e1 100644 --- a/app/code/Magento/AdvancedPricingImportExport/etc/export.xml +++ b/app/code/Magento/AdvancedPricingImportExport/etc/export.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdvancedPricingImportExport/etc/import.xml b/app/code/Magento/AdvancedPricingImportExport/etc/import.xml index 711a7bf270ce6..80c8873aad387 100644 --- a/app/code/Magento/AdvancedPricingImportExport/etc/import.xml +++ b/app/code/Magento/AdvancedPricingImportExport/etc/import.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdvancedPricingImportExport/etc/module.xml b/app/code/Magento/AdvancedPricingImportExport/etc/module.xml index 4ae0d6516e66f..f9ad9f34b2ad6 100644 --- a/app/code/Magento/AdvancedPricingImportExport/etc/module.xml +++ b/app/code/Magento/AdvancedPricingImportExport/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/AdvancedPricingImportExport/registration.php b/app/code/Magento/AdvancedPricingImportExport/registration.php index 86dcff3d60a68..a9477f3a9a1fb 100644 --- a/app/code/Magento/AdvancedPricingImportExport/registration.php +++ b/app/code/Magento/AdvancedPricingImportExport/registration.php @@ -1,6 +1,6 @@ subscriptionStatusProvider = $labelStatusProvider; + } + + /** + * Unset some non-related element parameters + * + * @param \Magento\Framework\Data\Form\Element\AbstractElement $element + * @return string + */ + public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) + { + $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue(); + $element->setData( + 'value', + $this->prepareLabelValue() + ); + return parent::render($element); + } + + /** + * Prepare label for subscription status + * + * @return string + */ + private function prepareLabelValue() + { + return __('Subscription status') . ': ' . __($this->subscriptionStatusProvider->getStatus()); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php new file mode 100644 index 0000000000000..56cc44bbc95dd --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php @@ -0,0 +1,118 @@ +subscription = $subscription; + $this->logger = $logger; + $this->notificationTime = $notificationTime; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Activate subscription to Magento Analytics via AJAX. + * + * @return Json + */ + public function execute() + { + try { + if ($this->getRequest()->getParam($this->subscriptionApprovedField)) { + $this->subscription->enable(); + } else { + $this->notificationTime->unsetLastTimeNotificationValue(); + } + $responseContent = [ + 'success' => true, + 'error_message' => '', + ]; + } catch (LocalizedException $e) { + $responseContent = [ + 'success' => false, + 'error_message' => $e->getMessage(), + ]; + $this->logger->error($e->getMessage()); + } catch (\Exception $e) { + $responseContent = [ + 'success' => false, + 'error_message' => __( + 'Sorry, there was an error processing your registration request to Magento Analytics. ' + . 'Please try again later.' + ), + ]; + $this->logger->error($e->getMessage()); + } + /** @var Json $resultJson */ + $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); + return $resultJson->setData($responseContent); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php new file mode 100644 index 0000000000000..b87730132e3d4 --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php @@ -0,0 +1,101 @@ +dateTimeFactory = $dateTimeFactory; + $this->notificationTime = $notificationTime; + $this->logger = $logger; + parent::__construct($context); + + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Postpones notification about subscription + * + * @return Json + */ + public function execute() + { + try { + $dateTime = $this->dateTimeFactory->create(); + $responseContent = [ + 'success' => $this->notificationTime->storeLastTimeNotification($dateTime->getTimestamp()), + 'error_message' => '' + ]; + } catch (LocalizedException $e) { + $this->logger->error($e->getMessage()); + $responseContent = [ + 'success' => false, + 'error_message' => $e->getMessage() + ]; + } catch (\Exception $e) { + $this->logger->error($e->getMessage()); + $responseContent = [ + 'success' => false, + 'error_message' => __('Error occurred during postponement notification') + ]; + } + /** @var Json $resultJson */ + $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); + return $resultJson->setData($responseContent); + } +} diff --git a/app/code/Magento/Analytics/Cron/SignUp.php b/app/code/Magento/Analytics/Cron/SignUp.php new file mode 100644 index 0000000000000..ef9e6320c2403 --- /dev/null +++ b/app/code/Magento/Analytics/Cron/SignUp.php @@ -0,0 +1,131 @@ +analyticsConnector = $analyticsConnector; + $this->configWriter = $configWriter; + $this->inboxFactory = $inboxFactory; + $this->inboxResource = $inboxResource; + $this->flagManager = $flagManager; + $this->reinitableConfig = $reinitableConfig; + } + + /** + * Execute scheduled subscription operation + * In case of failure writes message to notifications inbox + * + * @return bool + */ + public function execute() + { + $attemptsCount = $this->flagManager->getFlagData(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + if ($attemptsCount === null) { + $this->deleteAnalyticsCronExpr(); + return false; + } + + if ($attemptsCount <= 0) { + $this->deleteAnalyticsCronExpr(); + $this->flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + $inboxNotification = $this->inboxFactory->create(); + $inboxNotification->addNotice( + "Analytics subscription unsuccessful", + "Analytics subscription unsuccessful" + ); + $this->inboxResource->save($inboxNotification); + return false; + } + + $attemptsCount -= 1; + $this->flagManager->saveFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $attemptsCount); + $signUpResult = $this->analyticsConnector->execute('signUp'); + if ($signUpResult === false) { + return false; + } + + $this->deleteAnalyticsCronExpr(); + $this->flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + return true; + } + + /** + * Delete cron schedule setting into config. + * + * Delete cron schedule setting for subscription handler into config and + * re-initialize config cache to avoid auto-generate new schedule items. + * + * @return bool + */ + private function deleteAnalyticsCronExpr() + { + $this->configWriter->delete(SubscriptionHandler::CRON_STRING_PATH); + $this->reinitableConfig->reinit(); + return true; + } +} diff --git a/app/code/Magento/Analytics/LICENSE.txt b/app/code/Magento/Analytics/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/Analytics/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/Analytics/LICENSE_AFL.txt b/app/code/Magento/Analytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/Analytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/Analytics/Model/AnalyticsConnector.php b/app/code/Magento/Analytics/Model/AnalyticsConnector.php new file mode 100644 index 0000000000000..c50a1ba39ee5f --- /dev/null +++ b/app/code/Magento/Analytics/Model/AnalyticsConnector.php @@ -0,0 +1,56 @@ +commands = $commands; + $this->objectManager = $objectManager; + } + + /** + * Create the instance of the command and execute it. + * + * @param string $commandName + * @return bool + * @throws NotFoundException + */ + public function execute($commandName) + { + if (!array_key_exists($commandName, $this->commands)) { + throw new NotFoundException(__('Command was not found.')); + } + $command = $this->objectManager->create($this->commands[$commandName]); + return $command->execute(); + } +} diff --git a/app/code/Magento/Analytics/Model/AnalyticsConnector/AnalyticsCommandInterface.php b/app/code/Magento/Analytics/Model/AnalyticsConnector/AnalyticsCommandInterface.php new file mode 100644 index 0000000000000..27f9eb8ae4647 --- /dev/null +++ b/app/code/Magento/Analytics/Model/AnalyticsConnector/AnalyticsCommandInterface.php @@ -0,0 +1,21 @@ +analyticsToken = $analyticsToken; + $this->integrationManager = $integrationManager; + $this->signUpRequest = $signUpRequest; + } + + /** + * Executes signUp command + * + * During this call Magento generates or retrieves access token for the integration user + * In case successful generation Magento activates user and sends access token to MA + * As the response, Magento receives a token to MA + * Magento stores this token in System Configuration + * + * This method returns true in case of success + * + * @return bool + */ + public function execute() + { + $integrationToken = $this->integrationManager->generateToken(); + if ($integrationToken) { + $this->integrationManager->activateIntegration(); + $responseToken = $this->signUpRequest->call($integrationToken); + if ($responseToken) { + $this->analyticsToken->storeToken($responseToken); + } + } + return ((bool)$integrationToken && isset($responseToken) && (bool)$responseToken); + } +} diff --git a/app/code/Magento/Analytics/Model/AnalyticsConnector/SignUpRequest.php b/app/code/Magento/Analytics/Model/AnalyticsConnector/SignUpRequest.php new file mode 100644 index 0000000000000..ecdfc17e15c71 --- /dev/null +++ b/app/code/Magento/Analytics/Model/AnalyticsConnector/SignUpRequest.php @@ -0,0 +1,121 @@ +config = $config; + $this->httpClientFactory = $httpClientFactory; + $this->logger = $logger; + } + + /** + * Prepares json string with request data + * + * @param string $integrationToken + * @return string + */ + private function getRequestJson($integrationToken) + { + return json_encode( + [ + "token" => $integrationToken, + "url" => $this->config->getConfigDataValue(Store::XML_PATH_UNSECURE_BASE_URL) + ] + ); + } + + /** + * Extracts token from the response + * + * @param HttpResponse $response + * @return string|false + */ + private function extractResponseToken(HttpResponse $response) + { + $token = false; + if ($response->getStatus() === 200) { + $body = json_decode($response->getBody(), 1); + if (isset($body['token']) && !empty($body['token'])) { + $token = $body['token']; + } + } + return $token; + } + + /** + * Performs signUp call to MA + * Sends data about instance base url and integration user token + * Returns MA access token as a result + * + * @param string $integrationToken + * @return string|false + */ + public function call($integrationToken) + { + $token = false; + /** @var HttpClient $httpClient */ + $httpClient = $this->httpClientFactory->create(); + $httpClient->setUri($this->config->getConfigDataValue($this->signUpUrlPath)); + $httpClient->setRawData($this->getRequestJson($integrationToken)); + $httpClient->setMethod(HttpClient::POST); + try { + $token = $this->extractResponseToken($httpClient->request()); + if (!$token) { + $this->logger->warning('The attempt of subscription was unsuccessful on step sign-up.'); + } + } catch (\Exception $e) { + $this->logger->critical($e); + } + return $token; + } +} diff --git a/app/code/Magento/Analytics/Model/AnalyticsToken.php b/app/code/Magento/Analytics/Model/AnalyticsToken.php new file mode 100644 index 0000000000000..abef37f3a62d3 --- /dev/null +++ b/app/code/Magento/Analytics/Model/AnalyticsToken.php @@ -0,0 +1,92 @@ +reinitableConfig = $reinitableConfig; + $this->config = $config; + $this->configWriter = $configWriter; + } + + /** + * Get Magento BI token value. + * + * @return string|null + */ + public function getToken() + { + return $this->config->getValue($this->tokenPath); + } + + /** + * Stores Magento BI token value. + * + * @param string $value + * + * @return bool + */ + public function storeToken($value) + { + $this->configWriter->save($this->tokenPath, $value); + $this->reinitableConfig->reinit(); + + return true; + } + + /** + * Check Magento BI token value exist. + * + * @return bool + */ + public function isTokenExist() + { + return (bool)$this->getToken(); + } +} diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php new file mode 100644 index 0000000000000..a7dc93bcab800 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -0,0 +1,68 @@ +notificationTime = $notificationTime; + $this->dateTimeFactory = $dateTimeFactory; + } + + /** + * Validate is notification popup can be shown + * + * @return bool + */ + public function validate() + { + $lastNotificationTime = $this->notificationTime->getLastTimeNotification(); + if (!$lastNotificationTime) { + return false; + } + $datetime = $this->dateTimeFactory->create(); + return ( + $datetime->getTimestamp() >= $lastNotificationTime + $this->notificationInterval + ); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php new file mode 100644 index 0000000000000..8cbb64fb26337 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php @@ -0,0 +1,71 @@ +subscriptionHandler = $subscriptionHandler; + parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + } + + /** + * Add additional handling after config value was saved. + * + * @return Value + * @throws LocalizedException + */ + public function afterSave() + { + try { + $this->subscriptionHandler->process($this); + } catch (\Exception $e) { + $this->_logger->error($e->getMessage()); + throw new LocalizedException(__('There was an error save new configuration value.')); + } + + return parent::afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php new file mode 100644 index 0000000000000..5d6cae9f8fcb2 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -0,0 +1,153 @@ +configWriter = $configWriter; + $this->flagManager = $flagManager; + $this->analyticsToken = $analyticsToken; + $this->notificationTime = $notificationTime; + } + + /** + * Performs change subscription environment on config value change. + * + * Activate process of subscription handling + * if subscription was activated and Analytics token has not been received + * or interrupt subscription handling. + * + * @param Value $configValue + * + * @return bool + */ + public function process(Value $configValue) + { + if ($configValue->isValueChanged() && !$this->analyticsToken->isTokenExist()) { + $enabled = $configValue->getData('value'); + + if ($enabled) { + $this->setCronSchedule(); + $this->setAttemptsFlag(); + $this->notificationTime->unsetLastTimeNotificationValue(); + } else { + $this->unsetAttemptsFlag(); + } + } + + return true; + } + + /** + * Set cron schedule setting into config for activation of subscription process. + * + * @return bool + */ + private function setCronSchedule() + { + $cronExprArray = [ + '0', # Minute + '*', # Hour + '*', # Day of the Month + '*', # Month of the Year + '*', # Day of the Week + ]; + + $cronExprString = join(' ', $cronExprArray); + + $this->configWriter->save(self::CRON_STRING_PATH, $cronExprString); + + return true; + } + + /** + * Set flag as reserve counter of attempts subscription operation. + * + * @return bool + */ + private function setAttemptsFlag() + { + return $this->flagManager + ->saveFlag(self::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue); + } + + /** + * Unset flag of attempts subscription operation. + * + * @return bool + */ + private function unsetAttemptsFlag() + { + return $this->flagManager + ->deleteFlag(self::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + } +} diff --git a/app/code/Magento/Analytics/Model/FlagManager.php b/app/code/Magento/Analytics/Model/FlagManager.php new file mode 100644 index 0000000000000..47c8f0a0da2dd --- /dev/null +++ b/app/code/Magento/Analytics/Model/FlagManager.php @@ -0,0 +1,93 @@ +flagFactory = $flagFactory; + $this->flagResource = $flagResource; + } + + /** + * Return raw data from flag + * @param string $flagCode + * @return mixed + */ + public function getFlagData($flagCode) + { + return $this->getFlagObject($flagCode)->getFlagData(); + } + + /** + * Save flag by code + * @param string $flagCode + * @param mixed $value + * @return bool + */ + public function saveFlag($flagCode, $value) + { + $flag = $this->getFlagObject($flagCode); + $flag->setFlagData($value); + $this->flagResource->save($flag); + return true; + } + + /** + * Delete flag by code + * + * @param string $flagCode + * @return bool + */ + public function deleteFlag($flagCode) + { + $flag = $this->getFlagObject($flagCode); + if ($flag->getId()) { + $this->flagResource->delete($flag); + } + return true; + } + + /** + * Returns flag object + * + * @param string $flagCode + * @return Flag + */ + private function getFlagObject($flagCode) + { + /** @var Flag $flag */ + $flag = $this->flagFactory + ->create(['data' => ['flag_code' => $flagCode]]); + $this->flagResource->load($flag, $flagCode, 'flag_code'); + return $flag; + } +} diff --git a/app/code/Magento/Analytics/Model/IntegrationManager.php b/app/code/Magento/Analytics/Model/IntegrationManager.php new file mode 100644 index 0000000000000..de5c3ce5e3123 --- /dev/null +++ b/app/code/Magento/Analytics/Model/IntegrationManager.php @@ -0,0 +1,126 @@ +integrationService = $integrationService; + $this->config = $config; + $this->oauthService = $oauthService; + } + + /** + * Activate predefined integration user + * + * @return bool + * @throws NoSuchEntityException + */ + public function activateIntegration() + { + $integration = $this->integrationService->findByName( + $this->config->getConfigDataValue('analytics/integration_name') + ); + if (!$integration->getId()) { + throw new NoSuchEntityException(__('Cannot find predefined integration user!')); + } + $integrationData = $this->getIntegrationData(Integration::STATUS_ACTIVE); + $integrationData['integration_id'] = $integration->getId(); + $this->integrationService->update($integrationData); + return true; + } + + /** + * This method execute Generate Token command and enable integration + * + * @return bool|string + */ + public function generateToken() + { + $consumerId = $this->generateIntegration()->getConsumerId(); + $accessToken = $this->oauthService->getAccessToken($consumerId); + if (!$accessToken && $this->oauthService->createAccessToken($consumerId, true)) { + $accessToken = $this->oauthService->getAccessToken($consumerId); + } + return $accessToken; + } + + /** + * Returns consumer Id for MA integration user + * + * @return \Magento\Integration\Model\Integration + */ + private function generateIntegration() + { + $integration = $this->integrationService->findByName( + $this->config->getConfigDataValue('analytics/integration_name') + ); + if (!$integration->getId()) { + $integration = $this->integrationService->create($this->getIntegrationData()); + } + return $integration; + } + + /** + * Returns default attributes for MA integration user + * + * @param int $status + * @return array + */ + private function getIntegrationData($status = Integration::STATUS_INACTIVE) + { + $integrationData = [ + 'name' => $this->config->getConfigDataValue('analytics/integration_name'), + 'status' => $status, + 'all_resources' => false, + 'resource' => [ + 'Magento_Analytics::analytics', + 'Magento_Analytics::analytics_api' + ], + ]; + return $integrationData; + } +} diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php new file mode 100644 index 0000000000000..4df4cc970ee6d --- /dev/null +++ b/app/code/Magento/Analytics/Model/NotificationTime.php @@ -0,0 +1,65 @@ +flagManager = $flagManager; + } + + /** + * Stores last notification time + * + * @param string $value + * @return bool + */ + public function storeLastTimeNotification($value) + { + return $this->flagManager->saveFlag(self::NOTIFICATION_TIME, $value); + } + + /** + * Returns last time when merchant was notified about Analytic services + * + * @return int + */ + public function getLastTimeNotification() + { + return $this->flagManager->getFlagData(self::NOTIFICATION_TIME); + } + + /** + * Remove last notification time flag. + * + * @return bool + */ + public function unsetLastTimeNotificationValue() + { + return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME); + } +} diff --git a/app/code/Magento/Analytics/Model/Subscription.php b/app/code/Magento/Analytics/Model/Subscription.php new file mode 100644 index 0000000000000..e59fbcb1c3d70 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Subscription.php @@ -0,0 +1,108 @@ +configValueFactory = $configValueFactory; + $this->configStructure = $configStructure; + $this->configValueResource = $configValueResource; + $this->reinitableConfig = $reinitableConfig; + } + + /** + * Set subscription enabled config value. + * + * @return boolean + */ + public function enable() + { + /** @var Field $field */ + $field = $this->configStructure->getElement($this->enabledConfigStructurePath); + /** @var Value $configValue */ + $configValue = $field->hasBackendModel() + ? $field->getBackendModel() + : $this->configValueFactory->create(); + $configPath = $field->getConfigPath() ?: $this->enabledConfigStructurePath; + + $this->configValueResource + ->load($configValue, $configPath, 'path'); + + $configValue->setValue($this->yesValueDropdown); + $configValue->setPath($configPath); + + $this->configValueResource + ->save($configValue); + + $this->reinitableConfig->reinit(); + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php new file mode 100644 index 0000000000000..2a26740cdbf00 --- /dev/null +++ b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php @@ -0,0 +1,60 @@ +systemConfig = $systemConfig; + $this->analyticsToken = $analyticsToken; + } + + /** + * Statuses: + * + * Enabled - if subscription is enabled and MA token was received; + * Pending - if subscription is enabled and MA token was not received; + * Disabled - if subscription is not enabled. + * + * @return string + */ + public function getStatus() + { + $status = "Disabled"; + + if ($this->systemConfig->get('default/analytics/subscription/enabled')) { + $status = "Enabled"; + + if (!$this->analyticsToken->isTokenExist()) { + $status = "Pending"; + } + } + + return $status; + } +} diff --git a/app/code/Magento/Analytics/README.md b/app/code/Magento/Analytics/README.md new file mode 100644 index 0000000000000..5ca1a497bde73 --- /dev/null +++ b/app/code/Magento/Analytics/README.md @@ -0,0 +1 @@ +Analytics diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php new file mode 100644 index 0000000000000..b8d311ee5ea15 --- /dev/null +++ b/app/code/Magento/Analytics/Setup/InstallData.php @@ -0,0 +1,43 @@ +notificationTime = $notificationTime; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $this->notificationTime->storeLastTimeNotification(1); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php new file mode 100644 index 0000000000000..93a2fb6b1b19e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php @@ -0,0 +1,230 @@ +resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resultJsonMock = $this->getMockBuilder(Json::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subscriptionModelMock = $this->getMockBuilder(Subscription::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->activateController = $this->objectManagerHelper->getObject( + Activate::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'subscription' => $this->subscriptionModelMock, + 'logger' => $this->loggerMock, + 'notificationTime' => $this->notificationTimeMock, + '_request' => $this->requestMock, + 'subscriptionApprovedFiled' => $this->subscriptionApprovedField, + ] + ); + } + + /** + * @dataProvider executeDataProvider + * + * @param bool $isSubscriptionEnabled + * @return void + */ + public function testExecute($isSubscriptionEnabled) + { + $successResult = [ + 'success' => true, + 'error_message' => '', + ]; + + $this->requestMock + ->expects($this->once()) + ->method('getParam') + ->with($this->subscriptionApprovedField) + ->willReturn($isSubscriptionEnabled); + + if ($isSubscriptionEnabled) { + $this->subscriptionModelMock + ->expects($this->once()) + ->method('enable') + ->willReturn(true); + } else { + $this->notificationTimeMock + ->expects($this->once()) + ->method('unsetLastTimeNotificationValue') + ->willReturn(true); + } + + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultJsonMock); + $this->resultJsonMock->expects($this->once()) + ->method('setData') + ->with($successResult) + ->willReturnSelf(); + $this->assertSame( + $this->resultJsonMock, + $this->activateController->execute() + ); + } + + /** + * @dataProvider executeExceptionsDataProvider + * + * @param \Exception $exception + */ + public function testExecuteWithException(\Exception $exception) + { + $this->requestMock + ->expects($this->once()) + ->method('getParam') + ->with($this->subscriptionApprovedField) + ->willReturn(true); + + $this->subscriptionModelMock + ->expects($this->once()) + ->method('enable') + ->willThrowException($exception); + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultJsonMock); + + if ($exception instanceof LocalizedException) { + $this->resultJsonMock + ->expects($this->once()) + ->method('setData') + ->with([ + 'success' => false, + 'error_message' => $exception->getMessage(), + ]) + ->willReturnSelf(); + } else { + $this->resultJsonMock + ->expects($this->once()) + ->method('setData') + ->withAnyParameters() + ->willReturnSelf(); + } + + $this->assertSame( + $this->resultJsonMock, + $this->activateController->execute() + ); + } + + /** + * @return array + */ + public function executeExceptionsDataProvider() + { + return [ + [new LocalizedException(__('TestMessage'))], + [new \Exception('TestMessage')], + ]; + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + [true], + [false], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php new file mode 100644 index 0000000000000..78027298028d1 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php @@ -0,0 +1,168 @@ +dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->disableOriginalConstructor() + ->getMock(); + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->getMock(); + $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultMock = $this->getMockBuilder(Json::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultMock); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->action = $objectManagerHelper->getObject( + Postpone::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock, + 'notificationTime' => $this->notificationTimeMock, + 'logger' => $this->loggerMock + ] + ); + } + + public function testExecuteSuccess() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willReturn(true); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => true, + 'error_message' => '' + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } + + public function testExecuteFailedWithLocalizedException() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willThrowException(new LocalizedException(__('Error message'))); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => false, + 'error_message' => 'Error message' + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } + + public function testExecuteFailedWithException() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willThrowException(new \Exception('Any message')); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => false, + 'error_message' => __('Error occurred during postponement notification') + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php new file mode 100644 index 0000000000000..0568572854c05 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php @@ -0,0 +1,171 @@ +analyticsConnectorMock = $this->getMockBuilder(AnalyticsConnector::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->inboxFactoryMock = $this->getMockBuilder(InboxFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->inboxResourceMock = $this->getMockBuilder(InboxResource::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->inboxMock = $this->getMockBuilder(Inbox::class) + ->disableOriginalConstructor() + ->getMock(); + $this->reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->signUp = new SignUp( + $this->analyticsConnectorMock, + $this->configWriterMock, + $this->inboxFactoryMock, + $this->inboxResourceMock, + $this->flagManagerMock, + $this->reinitableConfigMock + ); + } + + public function testExecute() + { + $attemptsCount = 10; + + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($attemptsCount); + + $attemptsCount -= 1; + $this->flagManagerMock->expects($this->once()) + ->method('saveFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $attemptsCount); + $this->analyticsConnectorMock->expects($this->once()) + ->method('execute') + ->with('signUp') + ->willReturn(true); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->flagManagerMock->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + $this->assertTrue($this->signUp->execute()); + } + + public function testExecuteFlagNotExist() + { + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(null); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->assertFalse($this->signUp->execute()); + } + + public function testExecuteZeroAttempts() + { + $attemptsCount = 0; + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($attemptsCount); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->flagManagerMock->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + $this->inboxFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->inboxMock); + $this->inboxMock->expects($this->once()) + ->method('addNotice'); + $this->inboxResourceMock->expects($this->once()) + ->method('save') + ->with($this->inboxMock); + $this->assertFalse($this->signUp->execute()); + } + + /** + * Add assertions for method deleteAnalyticsCronExpr. + * + * @return void + */ + private function addDeleteAnalyticsCronExprAsserts() + { + $this->configWriterMock + ->expects($this->once()) + ->method('delete') + ->with(SubscriptionHandler::CRON_STRING_PATH) + ->willReturn(true); + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->willReturnSelf(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnector/SignUpCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnector/SignUpCommandTest.php new file mode 100644 index 0000000000000..747ada6fe7079 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnector/SignUpCommandTest.php @@ -0,0 +1,113 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + $this->integrationManagerMock = $this->getMockBuilder(IntegrationManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->signUpRequestMock = $this->getMockBuilder(SignUpRequest::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->signUpCommand = $objectManagerHelper->getObject( + SignUpCommand::class, + [ + 'analyticsToken' => $this->analyticsTokenMock, + 'integrationManager' => $this->integrationManagerMock, + 'signUpRequest' => $this->signUpRequestMock + ] + ); + } + + public function testExecuteSuccess() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn('IntegrationToken'); + $this->integrationManagerMock->expects($this->once()) + ->method('activateIntegration') + ->willReturn(true); + $this->signUpRequestMock->expects($this->once()) + ->method('call') + ->with('IntegrationToken') + ->willReturn('MAToken'); + $this->analyticsTokenMock->expects($this->once()) + ->method('storeToken') + ->with('MAToken') + ->willReturn(true); + $this->assertTrue($this->signUpCommand->execute()); + } + + public function testExecuteFailureCannotGenerateToken() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn(false); + $this->integrationManagerMock->expects($this->never()) + ->method('activateIntegration') + ->willReturn(true); + $this->signUpRequestMock->expects($this->never()) + ->method('call') + ->willReturn('MAToken'); + $this->analyticsTokenMock->expects($this->never()) + ->method('storeToken') + ->willReturn(true); + $this->assertFalse($this->signUpCommand->execute()); + } + + public function testExecuteFailureResponseIsEmpty() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn('IntegrationToken'); + $this->integrationManagerMock->expects($this->once()) + ->method('activateIntegration') + ->willReturn(true); + $this->signUpRequestMock->expects($this->once()) + ->method('call') + ->with('IntegrationToken') + ->willReturn(false); + $this->analyticsTokenMock->expects($this->never()) + ->method('storeToken'); + $this->assertFalse($this->signUpCommand->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnector/SignUpRequestTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnector/SignUpRequestTest.php new file mode 100644 index 0000000000000..c883c649dc4d9 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnector/SignUpRequestTest.php @@ -0,0 +1,218 @@ +configMock = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->httpClientFactoryMock = $this->getMockBuilder(HttpClientFactory::class) + ->setMethods(['create']) + ->getMock(); + $this->httpClientMock = $this->getMockBuilder(HttpClient::class) + ->getMock(); + $this->httpResponseMock = $this->getMockBuilder(HttpResponse::class) + ->disableOriginalConstructor() + ->getMock(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->signUpRequest = $objectManagerHelper->getObject( + SignUpRequest::class, + [ + 'config' => $this->configMock, + 'httpClientFactory' => $this->httpClientFactoryMock, + 'logger' => $this->loggerMock + ] + ); + } + + public function testCallSuccess() + { + $requestRawData = json_encode( + [ + 'token' => 'IntegrationToken', + 'url' => 'magento-url' + ] + ); + $responseRawData = json_encode( + [ + 'token' => 'MAToken' + ] + ); + $this->configMock->expects($this->exactly(2)) + ->method('getConfigDataValue') + ->willReturnMap( + [ + ['analytics/url/signup', null, null, 'ma-signup-url'], + [Store::XML_PATH_UNSECURE_BASE_URL, null, null, 'magento-url'] + ] + ); + $this->httpClientFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->httpClientMock); + $this->httpClientMock->expects($this->once()) + ->method('setUri') + ->with('ma-signup-url') + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('setRawData') + ->with($requestRawData) + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('setMethod') + ->with(HttpClient::POST) + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->willReturn($this->httpResponseMock); + $this->httpResponseMock->expects($this->once()) + ->method('getStatus') + ->willReturn(200); + $this->httpResponseMock->expects($this->once()) + ->method('getBody') + ->willReturn($responseRawData); + $this->assertEquals('MAToken', $this->signUpRequest->call('IntegrationToken')); + } + + public function testCallFailureEmptyResponse() + { + $requestRawData = json_encode( + [ + 'token' => 'IntegrationToken', + 'url' => 'magento-url' + ] + ); + $this->configMock->expects($this->exactly(2)) + ->method('getConfigDataValue') + ->willReturnMap( + [ + ['analytics/url/signup', null, null, 'ma-signup-url'], + [Store::XML_PATH_UNSECURE_BASE_URL, null, null, 'magento-url'] + ] + ); + $this->httpClientFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->httpClientMock); + $this->httpClientMock->expects($this->once()) + ->method('setUri') + ->with('ma-signup-url') + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('setRawData') + ->with($requestRawData) + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('setMethod') + ->with(HttpClient::POST) + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->willReturn($this->httpResponseMock); + $this->httpResponseMock->expects($this->once()) + ->method('getStatus') + ->willReturn(300); + $this->httpResponseMock->expects($this->never()) + ->method('getBody'); + $this->loggerMock->expects($this->once()) + ->method('warning') + ->with('The attempt of subscription was unsuccessful on step sign-up.'); + $this->assertEquals(false, $this->signUpRequest->call('IntegrationToken')); + } + + public function testCallFailureException() + { + $exception = new \Exception('exception'); + $requestRawData = json_encode( + [ + 'token' => 'IntegrationToken', + 'url' => 'magento-url' + ] + ); + $this->configMock->expects($this->exactly(2)) + ->method('getConfigDataValue') + ->willReturnMap( + [ + ['analytics/url/signup', null, null, 'ma-signup-url'], + [Store::XML_PATH_UNSECURE_BASE_URL, null, null, 'magento-url'] + ] + ); + $this->httpClientFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->httpClientMock); + $this->httpClientMock->expects($this->once()) + ->method('setUri') + ->with('ma-signup-url') + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('setRawData') + ->with($requestRawData) + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('setMethod') + ->with(HttpClient::POST) + ->willReturnSelf(); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->willThrowException($exception); + $this->httpResponseMock->expects($this->never()) + ->method('getStatus'); + $this->httpResponseMock->expects($this->never()) + ->method('getBody'); + $this->loggerMock->expects($this->never()) + ->method('warning'); + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with($exception); + $this->assertEquals(false, $this->signUpRequest->call('IntegrationToken')); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnectorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnectorTest.php new file mode 100644 index 0000000000000..3d15544e33d92 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsConnectorTest.php @@ -0,0 +1,70 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->signUpCommandMock = $this->getMockBuilder(SignUpCommand::class) + ->disableOriginalConstructor() + ->getMock(); + $this->commands = ['signUp' => SignUpCommand::class]; + $this->analyticsConnector = new AnalyticsConnector($this->commands, $this->objectManagerMock); + } + + public function testExecute() + { + $commandName = 'signUp'; + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with($this->commands[$commandName]) + ->willReturn($this->signUpCommandMock); + $this->signUpCommandMock->expects($this->once()) + ->method('execute') + ->willReturn(true); + $this->assertTrue($this->analyticsConnector->execute($commandName)); + } + + /** + * @expectedException \Magento\Framework\Exception\NotFoundException + */ + public function testExecuteCommandNotFound() + { + $commandName = 'register'; + $this->analyticsConnector->execute($commandName); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php new file mode 100644 index 0000000000000..2409ec7c110ca --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php @@ -0,0 +1,129 @@ +reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->tokenModel = $this->objectManagerHelper->getObject( + AnalyticsToken::class, + [ + 'reinitableConfig' => $this->reinitableConfigMock, + 'config' => $this->configMock, + 'configWriter' => $this->configWriterMock, + 'tokenPath' => $this->tokenPath, + ] + ); + } + + /** + * @return void + */ + public function testStoreToken() + { + $value = 'jjjj0000'; + + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with($this->tokenPath, $value); + + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->willReturnSelf(); + + $this->assertTrue($this->tokenModel->storeToken($value)); + } + + /** + * @return void + */ + public function testGetToken() + { + $value = 'jjjj0000'; + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->tokenPath) + ->willReturn($value); + + $this->assertSame($value, $this->tokenModel->getToken()); + } + + /** + * @return void + */ + public function testIsTokenExist() + { + $this->assertFalse($this->tokenModel->isTokenExist()); + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->tokenPath) + ->willReturn('0000'); + $this->assertTrue($this->tokenModel->isTokenExist()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php new file mode 100644 index 0000000000000..f361fde03f02d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -0,0 +1,81 @@ +dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->getMock(); + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); + $this->canViewNotification = $objectManager->getObject( + CanViewNotification::class, + [ + 'notificationTime' => $this->notificationTimeMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock + ] + ); + } + + public function testValidate() + { + $this->notificationTimeMock->expects($this->once()) + ->method('getLastTimeNotification') + ->willReturn(1); + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(10005000); + $this->assertTrue($this->canViewNotification->validate()); + } + + public function testValidateFlagRemoved() + { + $this->notificationTimeMock->expects($this->once()) + ->method('getLastTimeNotification') + ->willReturn(null); + $this->dateTimeFactoryMock->expects($this->never()) + ->method('create'); + $this->assertFalse($this->canViewNotification->validate()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php new file mode 100644 index 0000000000000..9eb0535580dff --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -0,0 +1,183 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->tokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configValueMock = $this->getMockBuilder(Value::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->subscriptionHandler = $this->objectManagerHelper->getObject( + SubscriptionHandler::class, + [ + 'flagManager' => $this->flagManagerMock, + 'configWriter' => $this->configWriterMock, + 'attemptsInitValue' => $this->attemptsInitValue, + 'analyticsToken' => $this->tokenMock, + 'notificationTime' => $this->notificationTimeMock, + ] + ); + } + + /** + * @param int|null $value null means that $value was not changed + * @param bool $isTokenExist + * + * @dataProvider processDataProvider + */ + public function testProcess($value, $isTokenExist) + { + $this->configValueMock + ->expects($this->once()) + ->method('isValueChanged') + ->willReturn(is_int($value)); + $this->tokenMock + ->expects(is_int($value) ? $this->once() : $this->never()) + ->method('isTokenExist') + ->willReturn($isTokenExist); + if (is_int($value) && !$isTokenExist) { + $this->configValueMock + ->expects($this->once()) + ->method('getData') + ->with('value') + ->willReturn($value); + + if ($value === 1) { + $this->addProcessWithEnabledTrueAsserts(); + } elseif ($value === 0) { + $this->addProcessWithEnabledFalseAsserts(); + } + } + $this->assertTrue( + $this->subscriptionHandler->process($this->configValueMock) + ); + } + + /** + * Add assertions for method process in case when new config value equals 1. + * + * @return void + */ + private function addProcessWithEnabledTrueAsserts() + { + $this->configWriterMock + ->expects($this->once()) + ->with(SubscriptionHandler::CRON_STRING_PATH, "0 * * * *") + ->method('save'); + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue) + ->willReturn(true); + $this->notificationTimeMock + ->expects($this->once()) + ->method('unsetLastTimeNotificationValue') + ->willReturn(true); + } + + /** + * Add assertions for method process in case when new config value equals 0. + * + * @return void + */ + private function addProcessWithEnabledFalseAsserts() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(true); + } + + /** + * Data provider for process test. + * + * @return array + */ + public function processDataProvider() + { + return [ + [null, true], + [null, false], + [0, true], + [1, true], + [0, false], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php new file mode 100644 index 0000000000000..336c80217b4c6 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php @@ -0,0 +1,99 @@ +subscriptionHandlerMock = $this->getMockBuilder(SubscriptionHandler::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->enabledModel = $this->objectManagerHelper->getObject( + Enabled::class, + [ + 'subscriptionHandler' => $this->subscriptionHandlerMock, + '_logger' => $this->loggerMock, + ] + ); + } + + /** + * @return void + */ + public function testAfterSaveSuccess() + { + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('process') + ->with($this->enabledModel) + ->willReturn(true); + + $this->assertInstanceOf( + Value::class, + $this->enabledModel->afterSave() + ); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testExecuteAfterSaveFailedWithLocalizedException() + { + $exception = new \Exception('Message'); + + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('process') + ->with($this->enabledModel) + ->willThrowException($exception); + + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + + $this->enabledModel->afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FlagManagerTest.php new file mode 100644 index 0000000000000..77abb0c87e1ea --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/FlagManagerTest.php @@ -0,0 +1,123 @@ +flagFactoryMock = $this->getMockBuilder(FlagFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagResourceMock = $this->getMockBuilder(FlagResource::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagMock = $this->getMockBuilder(Flag::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagManager = new FlagManager( + $this->flagFactoryMock, + $this->flagResourceMock + ); + } + + public function testGetFlagData() + { + $flagCode = "flag"; + $this->setupFlagObject($flagCode); + $this->flagMock->expects($this->once()) + ->method('getFlagData') + ->willReturn(10); + $this->assertEquals($this->flagManager->getFlagData($flagCode), 10); + } + + public function testSaveFlag() + { + $flagCode = "flag"; + $this->setupFlagObject($flagCode); + $this->flagMock->expects($this->once()) + ->method('setFlagData') + ->with(10); + $this->flagResourceMock->expects($this->once()) + ->method('save') + ->with($this->flagMock); + $this->assertTrue($this->flagManager->saveFlag($flagCode, 10)); + } + + /** + * @dataProvider flagExistDataProvider + * + * @param bool $isFlagExist + */ + public function testDeleteFlag($isFlagExist) + { + $flagCode = "flag"; + $this->setupFlagObject($flagCode); + $this->flagMock + ->expects($this->once()) + ->method('getId') + ->willReturn($isFlagExist); + if ($isFlagExist) { + $this->flagResourceMock + ->expects($this->once()) + ->method('delete') + ->with($this->flagMock); + } + $this->assertTrue($this->flagManager->deleteFlag($flagCode)); + } + + private function setupFlagObject($flagCode) + { + $this->flagFactoryMock->expects($this->once()) + ->method('create') + ->with(['data' => ['flag_code' => $flagCode]]) + ->willReturn($this->flagMock); + $this->flagResourceMock->expects($this->once()) + ->method('load') + ->with($this->flagMock, $flagCode, 'flag_code'); + } + + /** + * Provide variations of the flag existence. + * + * @return array + */ + public function flagExistDataProvider() + { + return [ + [true], + [false] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php new file mode 100644 index 0000000000000..14af7c7e66e99 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php @@ -0,0 +1,228 @@ +integrationServiceMock = $this->getMockBuilder(IntegrationServiceInterface::class) + ->getMock(); + $this->configMock = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->oauthServiceMock = $this->getMockBuilder(OauthServiceInterface::class) + ->getMock(); + $this->integrationMock = $this->getMockBuilder(Integration::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getId', + 'getConsumerId' + ]) + ->getMock(); + $this->integrationManager = $objectManagerHelper->getObject( + IntegrationManager::class, + [ + 'integrationService' => $this->integrationServiceMock, + 'oauthService' => $this->oauthServiceMock, + 'config' => $this->configMock + ] + ); + } + + /** + * @param string $status + * + * @return array + */ + private function getIntegrationUserData($status) + { + return [ + 'name' => 'ma-integration-user', + 'status' => $status, + 'all_resources' => false, + 'resource' => [ + 'Magento_Analytics::analytics', + 'Magento_Analytics::analytics_api' + ], + ]; + } + + /** + * @return void + */ + public function testActivateIntegrationSuccess() + { + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->exactly(2)) + ->method('getId') + ->willReturn(100500); + $integrationData = $this->getIntegrationUserData(Integration::STATUS_ACTIVE); + $integrationData['integration_id'] = 100500; + $this->configMock->expects($this->exactly(2)) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('update') + ->with($integrationData); + $this->assertTrue($this->integrationManager->activateIntegration()); + } + + /** + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + */ + public function testActivateIntegrationFailureNoSuchEntity() + { + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn(null); + $this->configMock->expects($this->once()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->never()) + ->method('update'); + $this->integrationManager->activateIntegration(); + } + + /** + * @dataProvider integrationIdDataProvider + * + * @param int|null $integrationId If null integration is absent. + * @return void + */ + public function testGetTokenNewIntegration($integrationId) + { + $this->configMock->expects($this->atLeastOnce()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getConsumerId') + ->willReturn(100500); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn($integrationId); + if (!$integrationId) { + $this->integrationServiceMock + ->expects($this->once()) + ->method('create') + ->with($this->getIntegrationUserData(Integration::STATUS_INACTIVE)) + ->willReturn($this->integrationMock); + } + $this->oauthServiceMock->expects($this->at(0)) + ->method('getAccessToken') + ->with(100500) + ->willReturn(false); + $this->oauthServiceMock->expects($this->at(2)) + ->method('getAccessToken') + ->with(100500) + ->willReturn('IntegrationToken'); + $this->oauthServiceMock->expects($this->once()) + ->method('createAccessToken') + ->with(100500, true) + ->willReturn(true); + $this->assertEquals('IntegrationToken', $this->integrationManager->generateToken()); + } + + /** + * @dataProvider integrationIdDataProvider + * + * @param int|null $integrationId If null integration is absent. + * @return void + */ + public function testGetTokenExistingIntegration($integrationId) + { + $this->configMock->expects($this->atLeastOnce()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getConsumerId') + ->willReturn(100500); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn($integrationId); + if (!$integrationId) { + $this->integrationServiceMock + ->expects($this->once()) + ->method('create') + ->with($this->getIntegrationUserData(Integration::STATUS_INACTIVE)) + ->willReturn($this->integrationMock); + } + $this->oauthServiceMock->expects($this->once()) + ->method('getAccessToken') + ->with(100500) + ->willReturn('IntegrationToken'); + $this->oauthServiceMock->expects($this->never()) + ->method('createAccessToken'); + $this->assertEquals('IntegrationToken', $this->integrationManager->generateToken()); + } + + /** + * @return array + */ + public function integrationIdDataProvider() + { + return [ + [1], + [null], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php new file mode 100644 index 0000000000000..78bb694645fe8 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php @@ -0,0 +1,76 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->notificationTime = $objectManagerHelper->getObject( + NotificationTime::class, + [ + 'flagManager' => $this->flagManagerMock, + ] + ); + } + + public function testStoreLastTimeNotification() + { + $value = 100500; + + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(NotificationTime::NOTIFICATION_TIME, $value) + ->willReturn(true); + $this->assertTrue($this->notificationTime->storeLastTimeNotification($value)); + } + + public function testGetLastTimeNotification() + { + $value = 100500; + + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(NotificationTime::NOTIFICATION_TIME) + ->willReturn(true); + $this->assertEquals($value, $this->notificationTime->getLastTimeNotification()); + } + + public function testUnsetLastTimeNotificationValue() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(NotificationTime::NOTIFICATION_TIME) + ->willReturn(true); + $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValue()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php new file mode 100644 index 0000000000000..4e32308d51e3c --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php @@ -0,0 +1,94 @@ +systemConfigMock = $this->getMockBuilder(System::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->statusProvider = $this->objectManagerHelper->getObject( + SubscriptionStatusProvider::class, + [ + 'systemConfig' => $this->systemConfigMock, + 'analyticsToken' => $this->analyticsTokenMock + ] + ); + } + + /** + * @dataProvider statusDataProvider + * + * @param bool $isSubscriptionEnabled + * @param bool $hasToken + * @param int $attempts + * @param string $expectedStatus + */ + public function testGetStatus($isSubscriptionEnabled, $hasToken, $attempts, $expectedStatus) + { + $this->analyticsTokenMock->expects($this->exactly($attempts)) + ->method('isTokenExist') + ->willReturn($hasToken); + $this->systemConfigMock->expects($this->once()) + ->method('get') + ->with('default/analytics/subscription/enabled') + ->willReturn($isSubscriptionEnabled); + $this->assertEquals($expectedStatus, $this->statusProvider->getStatus()); + } + + /** + * @return array + */ + public function statusDataProvider() + { + return [ + 'TestWithEnabledStatus' => [true, true, 1, "Enabled"], + 'TestWithPendingStatus' => [true, false, 1, "Pending"], + 'TestWithDisabledStatus' => [false, false, 0, "Disabled"], + 'TestWithDisabledStatus2' => [false, true, 0, "Disabled"], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionTest.php b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionTest.php new file mode 100644 index 0000000000000..693b97cb0aff2 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionTest.php @@ -0,0 +1,197 @@ +configValueFactoryMock = $this->getMockBuilder(ValueFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configValueMock = $this->getMockBuilder(Value::class) + ->disableOriginalConstructor() + ->setMethods(['setValue', 'setPath']) + ->getMock(); + + $this->configStructureMock = $this->getMockBuilder(SearchInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configValueResourceMock = $this->getMockBuilder(AbstractDb::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->elementFieldMock = $this->getMockBuilder(Field::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->subscriptionModel = $this->objectManagerHelper->getObject( + SubscriptionModel::class, + [ + 'configValueFactory' => $this->configValueFactoryMock, + 'configStructure' => $this->configStructureMock, + 'configValueResource' => $this->configValueResourceMock, + 'reinitableConfig' => $this->reinitableConfigMock, + 'enabledConfigStructurePath' => $this->enableConfigStructurePath, + 'yesValueDropdown' => $this->yesValueDropdown, + ] + ); + } + + /** + * @dataProvider enabledDataProvider + * + * @param boolean $backendModel + * @param string $configPath + * + * @return void + */ + public function testEnabled($backendModel, $configPath) + { + $this->configStructureMock + ->expects($this->once()) + ->method('getElement') + ->with($this->enableConfigStructurePath) + ->willReturn($this->elementFieldMock); + $this->elementFieldMock + ->expects($this->once()) + ->method('hasBackendModel') + ->willReturn($backendModel); + if ($backendModel) { + $this->elementFieldMock + ->expects($this->once()) + ->method('getBackendModel') + ->willReturn($this->configValueMock); + } else { + $this->configValueFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($this->configValueMock); + } + $this->elementFieldMock + ->expects($this->once()) + ->method('getConfigPath') + ->willReturn($configPath); + $configPath = $configPath ?: $this->enableConfigStructurePath; + $this->configValueResourceMock + ->expects($this->once()) + ->method('load') + ->with($this->configValueMock, $configPath, 'path') + ->willReturnSelf(); + $this->configValueMock + ->expects($this->once()) + ->method('setValue') + ->with(1) + ->willReturnSelf(); + $this->configValueMock + ->expects($this->once()) + ->method('setPath') + ->with($configPath) + ->willReturnSelf(); + $this->configValueResourceMock + ->expects($this->once()) + ->method('save') + ->with($this->configValueMock) + ->willReturnSelf(); + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->willReturnSelf(); + $this->assertTrue($this->subscriptionModel->enable()); + } + + /** + * @return array + */ + public function enabledDataProvider() + { + return [ + 'TestWithBackendModelWithoutConfigPath' => [true, null], + 'TestWithBackendModelWithConfigPath' => [true, $this->configPath], + 'TestWithoutBackendModelWithoutConfigPath' => [false, null], + 'TestWithoutBackendModelWithConfigPath' => [false, $this->configPath], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php new file mode 100644 index 0000000000000..8e0cd06ef272b --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php @@ -0,0 +1,228 @@ + 'value']; + + /** + * @return void + */ + protected function setUp() + { + $this->searchResultMock = $this->getMockBuilder(SearchResultInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->searchCriteriaMock = $this->getMockBuilder(SearchCriteriaInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->dataCollectionMock = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->filterMock = $this->getMockBuilder(Filter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->dummyDataProvider = $this->objectManagerHelper->getObject( + DummyDataProvider::class, + [ + 'name' => $this->providerName, + 'searchResult' => $this->searchResultMock, + 'searchCriteria' => $this->searchCriteriaMock, + 'collection' => $this->dataCollectionMock, + 'data' => ['config' => $this->configData], + ] + ); + } + + /** + * @return void + */ + public function testGetName() + { + $this->assertSame($this->providerName, $this->dummyDataProvider->getName()); + } + + /** + * @return void + */ + public function testGetConfigData() + { + $this->assertSame($this->configData, $this->dummyDataProvider->getConfigData()); + $dataProvider = $this->objectManagerHelper + ->getObject( + DummyDataProvider::class, + [] + ); + $this->assertSame([], $dataProvider->getConfigData()); + } + + /** + * @return void + */ + public function testSetConfigData() + { + $configValue = ['key' => 'value']; + + $this->assertTrue($this->dummyDataProvider->setConfigData($configValue)); + $this->assertSame($configValue, $this->dummyDataProvider->getConfigData()); + } + + /** + * @return void + */ + public function testGetMeta() + { + $this->assertSame([], $this->dummyDataProvider->getMeta()); + } + + /** + * @return void + */ + public function testGetFieldMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldMetaInfo('', '')); + } + + /** + * @return void + */ + public function testGetFieldSetMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldSetMetaInfo('')); + } + + /** + * @return void + */ + public function testGetFieldsMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldsMetaInfo('')); + } + + /** + * @return void + */ + public function testGetPrimaryFieldName() + { + $this->assertSame('', $this->dummyDataProvider->getPrimaryFieldName()); + } + + /** + * @return void + */ + public function testGetRequestFieldName() + { + $this->assertSame('', $this->dummyDataProvider->getRequestFieldName()); + } + + /** + * @return void + */ + public function testGetData() + { + $this->dataCollectionMock + ->expects($this->once()) + ->method('toArray') + ->willReturn([]); + $this->assertSame([], $this->dummyDataProvider->getData()); + } + + /** + * @return void + */ + public function testAddFilter() + { + $this->assertNull($this->dummyDataProvider->addFilter($this->filterMock)); + } + + /** + * @return void + */ + public function testAddOrder() + { + $this->assertNull($this->dummyDataProvider->addOrder('', '')); + } + + /** + * @return void + */ + public function testSetLimit() + { + $this->assertNull($this->dummyDataProvider->setLimit(1, 1)); + } + + /** + * @return void + */ + public function testGetSearchCriteria() + { + $this->assertSame($this->searchCriteriaMock, $this->dummyDataProvider->getSearchCriteria()); + } + + /** + * @return void + */ + public function testGetSearchResult() + { + $this->assertSame($this->searchResultMock, $this->dummyDataProvider->getSearchResult()); + } +} diff --git a/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php new file mode 100644 index 0000000000000..e842b6572b8c2 --- /dev/null +++ b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php @@ -0,0 +1,237 @@ +name = $name; + $this->searchResult = $searchResult; + $this->searchCriteria = $searchCriteria; + $this->collection = $collection; + $this->data = $data; + } + + /** + * Get Data Provider name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get config data + * + * @return mixed + */ + public function getConfigData() + { + return isset($this->data['config']) ? $this->data['config'] : []; + } + + /** + * Set config data + * + * @param mixed $config + * + * @return bool + */ + public function setConfigData($config) + { + $this->data['config'] = $config; + + return true; + } + + /** + * @return array + */ + public function getMeta() + { + return []; + } + + /** + * @param string $fieldSetName + * @param string $fieldName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function getFieldMetaInfo($fieldSetName, $fieldName) + { + return []; + } + + /** + * Get field set meta info + * + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function getFieldSetMetaInfo($fieldSetName) + { + return []; + } + + /** + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function getFieldsMetaInfo($fieldSetName) + { + return []; + } + + /** + * Get primary field name + * + * @return string + */ + public function getPrimaryFieldName() + { + return ''; + } + + /** + * Get field name in request + * + * @return string + */ + public function getRequestFieldName() + { + return ''; + } + + /** + * Get data + * + * @return mixed + */ + public function getData() + { + return $this->collection->toArray(); + } + + /** + * Add field filter to collection + * + * @param \Magento\Framework\Api\Filter $filter + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function addFilter(\Magento\Framework\Api\Filter $filter) + { + } + + /** + * Add ORDER BY to the end or to the beginning + * + * @param string $field + * @param string $direction + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function addOrder($field, $direction) + { + } + + /** + * Set Query limit + * + * @param int $offset + * @param int $size + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setLimit($offset, $size) + { + } + + /** + * Returns search criteria + * + * @return SearchCriteriaInterface + */ + public function getSearchCriteria() + { + return $this->searchCriteria; + } + + /** + * @return SearchResultInterface + */ + public function getSearchResult() + { + return $this->searchResult; + } +} diff --git a/app/code/Magento/Analytics/composer.json b/app/code/Magento/Analytics/composer.json new file mode 100644 index 0000000000000..b8d05bbd08a52 --- /dev/null +++ b/app/code/Magento/Analytics/composer.json @@ -0,0 +1,27 @@ +{ + "name": "magento/module-analytics", + "description": "N/A", + "require": { + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", + "magento/module-backend": "100.2.*", + "magento/module-admin-notification": "100.2.*", + "magento/module-config": "100.2.*", + "magento/module-integration": "100.2.*", + "magento/module-store": "100.2.*", + "magento/framework": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\Analytics\\": "" + } + } +} diff --git a/app/code/Magento/Analytics/etc/acl.xml b/app/code/Magento/Analytics/etc/acl.xml new file mode 100644 index 0000000000000..93e81a2380734 --- /dev/null +++ b/app/code/Magento/Analytics/etc/acl.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/routes.xml b/app/code/Magento/Analytics/etc/adminhtml/routes.xml new file mode 100644 index 0000000000000..232ebe94d314f --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/routes.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml new file mode 100644 index 0000000000000..1472221562baf --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -0,0 +1,28 @@ + + + + +
+ + general + Magento_Analytics::analytics_settings + + + + + Magento\Config\Model\Config\Source\Yesno + Magento\Analytics\Model\Config\Backend\Enabled + analytics/subscription/enabled + + + Magento\Analytics\Block\Adminhtml\System\Config\SubscriptionStatusLabel + + +
+
+
diff --git a/app/code/Magento/Analytics/etc/config.xml b/app/code/Magento/Analytics/etc/config.xml new file mode 100644 index 0000000000000..6e628e568844f --- /dev/null +++ b/app/code/Magento/Analytics/etc/config.xml @@ -0,0 +1,21 @@ + + + + + + + + + + http://drakelair1.corp.magento.com/mamock/signup + http://drakelair1.corp.magento.com/mamock/update + + Magento Analytics user + + + diff --git a/app/code/Magento/Analytics/etc/crontab.xml b/app/code/Magento/Analytics/etc/crontab.xml new file mode 100644 index 0000000000000..aac51f4417362 --- /dev/null +++ b/app/code/Magento/Analytics/etc/crontab.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/app/code/Magento/Analytics/etc/di.xml b/app/code/Magento/Analytics/etc/di.xml new file mode 100644 index 0000000000000..2467f5da2bb00 --- /dev/null +++ b/app/code/Magento/Analytics/etc/di.xml @@ -0,0 +1,28 @@ + + + + + + + Magento\Analytics\Model\AnalyticsConnector\SignUpCommand + + + + + + + Magento\Analytics\Model\Condition\CanViewNotification + + + + + + Magento\Config\Model\ResourceModel\Config\Data + + + diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml new file mode 100644 index 0000000000000..958d43cd6ee53 --- /dev/null +++ b/app/code/Magento/Analytics/etc/module.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/registration.php b/app/code/Magento/Analytics/registration.php new file mode 100644 index 0000000000000..d07fe8ffb5e56 --- /dev/null +++ b/app/code/Magento/Analytics/registration.php @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml new file mode 100644 index 0000000000000..60f3751d74bd4 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml @@ -0,0 +1,114 @@ + + +
+ + + analytics_subscription_form.analytics_subscription_form_data_source + analytics_subscription_form.analytics_subscription_form_data_source + + Analytics Subscription + + data + analytics_subscription_form + simple + true + + templates/form/collapsible + + + + + Magento\Analytics\Ui\DataProvider\DummyDataProvider + analytics_subscription_form_data_source + + + + + + false + + + + + + + Magento_Ui/js/form/provider + + + + + + + + Magento_Analytics/js/modal/modal-component + actionCancel + true + + Subscription Confirmation + popup + true + true + true + + + Cancel + action-secondary + + + ${ $.name } + actionCancel + + + + + Ok + action-primary + + + ${ $.parentName } + save + + + ${ $.name } + closeModal + + + + + + + + +
+ + + + + + + + + + admin__field-wide + I agree with sending my system + configuration and transaction data to Magento Analytics. + + checkbox + analytics_subscription_checkbox + + 1 + 0 + + 1 + + + +
+
+
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js new file mode 100644 index 0000000000000..4b215db24857a --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js @@ -0,0 +1,66 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'Magento_Ui/js/modal/modal-component', + 'Magento_Ui/js/modal/alert', + 'mage/translate' +], function ($, Modal, alert, $t) { + 'use strict'; + + return Modal.extend({ + defaults: { + postponeOptions: {}, + imports: { + postponeUrl: '${ $.provider }:postpone_url' + }, + modules: { + form: '${ $.parentName }' + } + }, + + /** + * Send request to postpone modal appearance for a certain time. + * + * @param {Object} options - additional request options. + */ + sendPostponeRequest: function (options) { + var self = this, + data = $.extend(this.form().source.data, options); + + $.ajax({ + type: 'POST', + url: this.postponeUrl, + data: data, + showLoader: true + }).done(function (xhr) { + if (xhr.error) { + self.onError(xhr); + } + }).fail(this.onError); + }, + + /** + * Error handler. + * + * @param {Object} xhr - request result. + */ + onError: function (xhr) { + if (xhr.statusText === 'abort') { + return; + } + + alert({ + content: xhr.message || $t('An error occurred while subscription process.') + }); + }, + + /** @inheritdoc */ + actionCancel: function () { + this.sendPostponeRequest(this.postponeOptions); + this.closeModal(); + } + }); +}); diff --git a/app/code/Magento/Authorization/Model/Acl/AclRetriever.php b/app/code/Magento/Authorization/Model/Acl/AclRetriever.php index d3a5714c93743..5b67748cd2e41 100644 --- a/app/code/Magento/Authorization/Model/Acl/AclRetriever.php +++ b/app/code/Magento/Authorization/Model/Acl/AclRetriever.php @@ -1,6 +1,6 @@ _resource = $resource; $this->_groupFactory = $groupFactory; $this->_roleFactory = $roleFactory; + $this->aclDataCache = $aclDataCache ?: ObjectManager::getInstance()->get( + \Magento\Framework\Acl\Data\CacheInterface::class + ); + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->cacheKey = $cacheKey; } /** @@ -49,12 +81,7 @@ public function __construct( */ public function populateAcl(\Magento\Framework\Acl $acl) { - $roleTableName = $this->_resource->getTableName('authorization_role'); - $connection = $this->_resource->getConnection(); - - $select = $connection->select()->from($roleTableName)->order('tree_level'); - - foreach ($connection->fetchAll($select) as $role) { + foreach ($this->getRolesArray() as $role) { $parent = $role['parent_id'] > 0 ? $role['parent_id'] : null; switch ($role['role_type']) { case RoleGroup::ROLE_TYPE: @@ -71,4 +98,28 @@ public function populateAcl(\Magento\Framework\Acl $acl) } } } + + /** + * Get application ACL roles array + * + * @return array + */ + private function getRolesArray() + { + $rolesCachedData = $this->aclDataCache->load($this->cacheKey); + if ($rolesCachedData) { + return $this->serializer->unserialize($rolesCachedData); + } + + $roleTableName = $this->_resource->getTableName('authorization_role'); + $connection = $this->_resource->getConnection(); + + $select = $connection->select() + ->from($roleTableName) + ->order('tree_level'); + + $rolesArray = $connection->fetchAll($select); + $this->aclDataCache->save($this->serializer->serialize($rolesArray), $this->cacheKey); + return $rolesArray; + } } diff --git a/app/code/Magento/Authorization/Model/Acl/Loader/Rule.php b/app/code/Magento/Authorization/Model/Acl/Loader/Rule.php index 2fa86b63ae504..8f89e00cfb22e 100644 --- a/app/code/Magento/Authorization/Model/Acl/Loader/Rule.php +++ b/app/code/Magento/Authorization/Model/Acl/Loader/Rule.php @@ -1,32 +1,69 @@ _resource = $resource; $this->_rootResource = $rootResource; + $this->aclDataCache = $aclDataCache ?: ObjectManager::getInstance()->get( + \Magento\Framework\Acl\Data\CacheInterface::class + ); + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->cacheKey = $cacheKey; } /** @@ -37,15 +74,7 @@ public function __construct( */ public function populateAcl(\Magento\Framework\Acl $acl) { - $ruleTable = $this->_resource->getTableName("authorization_rule"); - - $connection = $this->_resource->getConnection(); - - $select = $connection->select()->from(['r' => $ruleTable]); - - $rulesArr = $connection->fetchAll($select); - - foreach ($rulesArr as $rule) { + foreach ($this->getRulesArray() as $rule) { $role = $rule['role_id']; $resource = $rule['resource_id']; $privileges = !empty($rule['privileges']) ? explode(',', $rule['privileges']) : null; @@ -62,4 +91,28 @@ public function populateAcl(\Magento\Framework\Acl $acl) } } } + + /** + * Get application ACL rules array. + * + * @return array + */ + private function getRulesArray() + { + $rulesCachedData = $this->aclDataCache->load($this->cacheKey); + if ($rulesCachedData) { + return $this->serializer->unserialize($rulesCachedData); + } + + $ruleTable = $this->_resource->getTableName("authorization_rule"); + $connection = $this->_resource->getConnection(); + $select = $connection->select() + ->from(['r' => $ruleTable]); + + $rulesArr = $connection->fetchAll($select); + + $this->aclDataCache->save($this->serializer->serialize($rulesArr), $this->cacheKey); + + return $rulesArr; + } } diff --git a/app/code/Magento/Authorization/Model/Acl/Role/Generic.php b/app/code/Magento/Authorization/Model/Acl/Role/Generic.php index f35a755b74045..b6a92d5ccae27 100644 --- a/app/code/Magento/Authorization/Model/Acl/Role/Generic.php +++ b/app/code/Magento/Authorization/Model/Acl/Role/Generic.php @@ -1,6 +1,6 @@ _aclBuilder = $aclBuilder; parent::__construct($context, $connectionName); $this->_rootResource = $rootResource; $this->_aclCache = $aclCache; $this->_logger = $logger; + $this->aclDataCache = $aclDataCache ?: ObjectManager::getInstance()->get( + \Magento\Framework\Acl\Data\CacheInterface::class + ); } /** @@ -79,8 +92,8 @@ protected function _construct() */ public function saveRel(\Magento\Authorization\Model\Rules $rule) { + $connection = $this->getConnection(); try { - $connection = $this->getConnection(); $connection->beginTransaction(); $roleId = $rule->getRoleId(); @@ -118,7 +131,7 @@ public function saveRel(\Magento\Authorization\Model\Rules $rule) } $connection->commit(); - $this->_aclCache->clean(); + $this->aclDataCache->clean(); } catch (\Magento\Framework\Exception\LocalizedException $e) { $connection->rollBack(); throw $e; diff --git a/app/code/Magento/Authorization/Model/ResourceModel/Rules/Collection.php b/app/code/Magento/Authorization/Model/ResourceModel/Rules/Collection.php index e4bb8f1195322..9aec756931868 100644 --- a/app/code/Magento/Authorization/Model/ResourceModel/Rules/Collection.php +++ b/app/code/Magento/Authorization/Model/ResourceModel/Rules/Collection.php @@ -1,6 +1,6 @@ _resourceMock = $this->getMock( @@ -57,51 +72,82 @@ protected function setUp() false ); - $this->_resourceMock->expects( - $this->once() - )->method( - 'getTableName' - )->with( - $this->equalTo('authorization_role') - )->will( - $this->returnArgument(1) - ); - - $selectMock = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false); - $selectMock->expects($this->any())->method('from')->will($this->returnValue($selectMock)); + $this->selectMock = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false); + $this->selectMock->expects($this->any()) + ->method('from') + ->will($this->returnValue($this->selectMock)); $this->_adapterMock = $this->getMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, [], [], '', false); - $this->_adapterMock->expects($this->once())->method('select')->will($this->returnValue($selectMock)); - - $this->_resourceMock->expects( - $this->once() - )->method( - 'getConnection' - )->will( - $this->returnValue($this->_adapterMock) + + $this->serializerMock = $this->getMock( + \Magento\Framework\Serialize\Serializer\Json::class, + ['serialize', 'unserialize'], + [], + '', + false + ); + $this->serializerMock->expects($this->any()) + ->method('serialize') + ->will( + $this->returnCallback( + function ($value) { + return json_encode($value); + } + ) + ); + + $this->serializerMock->expects($this->any()) + ->method('unserialize') + ->will( + $this->returnCallback( + function ($value) { + return json_decode($value, true); + } + ) + ); + + $this->aclDataCacheMock = $this->getMock( + \Magento\Framework\Acl\Data\CacheInterface::class, + [], + [], + '', + false ); $this->_model = new \Magento\Authorization\Model\Acl\Loader\Role( $this->_groupFactoryMock, $this->_roleFactoryMock, - $this->_resourceMock + $this->_resourceMock, + $this->aclDataCacheMock, + $this->serializerMock ); } public function testPopulateAclAddsRolesAndTheirChildren() { - $this->_adapterMock->expects( - $this->once() - )->method( - 'fetchAll' - )->will( - $this->returnValue( - [ - ['role_id' => 1, 'role_type' => 'G', 'parent_id' => null], - ['role_id' => 2, 'role_type' => 'U', 'parent_id' => 1, 'user_id' => 1], - ] - ) - ); + $this->_resourceMock->expects($this->once()) + ->method('getTableName') + ->with($this->equalTo('authorization_role')) + ->will($this->returnArgument(1)); + + $this->_adapterMock->expects($this->once()) + ->method('select') + ->will($this->returnValue($this->selectMock)); + + $this->_resourceMock->expects($this->once()) + ->method('getConnection') + ->will($this->returnValue($this->_adapterMock)); + + $this->_adapterMock->expects($this->once()) + ->method('fetchAll') + ->will( + $this->returnValue( + [ + ['role_id' => 1, 'role_type' => 'G', 'parent_id' => null], + ['role_id' => 2, 'role_type' => 'U', 'parent_id' => 1, 'user_id' => 1], + ] + ) + ); $this->_groupFactoryMock->expects($this->once())->method('create')->with(['roleId' => '1']); $this->_roleFactoryMock->expects($this->once())->method('create')->with(['roleId' => '2']); @@ -115,13 +161,55 @@ public function testPopulateAclAddsRolesAndTheirChildren() public function testPopulateAclAddsMultipleParents() { - $this->_adapterMock->expects( - $this->once() - )->method( - 'fetchAll' - )->will( - $this->returnValue([['role_id' => 1, 'role_type' => 'U', 'parent_id' => 2, 'user_id' => 3]]) - ); + $this->_resourceMock->expects($this->once()) + ->method('getTableName') + ->with($this->equalTo('authorization_role')) + ->will($this->returnArgument(1)); + + $this->_adapterMock->expects($this->once()) + ->method('select') + ->will($this->returnValue($this->selectMock)); + + $this->_resourceMock->expects($this->once()) + ->method('getConnection') + ->will($this->returnValue($this->_adapterMock)); + + $this->_adapterMock->expects($this->once()) + ->method('fetchAll') + ->will($this->returnValue([['role_id' => 1, 'role_type' => 'U', 'parent_id' => 2, 'user_id' => 3]])); + + $this->_roleFactoryMock->expects($this->never())->method('getModelInstance'); + $this->_groupFactoryMock->expects($this->never())->method('getModelInstance'); + + $aclMock = $this->getMock(\Magento\Framework\Acl::class); + $aclMock->expects($this->at(0))->method('hasRole')->with('1')->will($this->returnValue(true)); + $aclMock->expects($this->at(1))->method('addRoleParent')->with('1', '2'); + + $this->_model->populateAcl($aclMock); + } + + public function testPopulateAclFromCache() + { + $this->_resourceMock->expects($this->never())->method('getConnection'); + $this->_resourceMock->expects($this->never())->method('getTableName'); + $this->_adapterMock->expects($this->never())->method('fetchAll'); + $this->aclDataCacheMock->expects($this->once()) + ->method('load') + ->with(\Magento\Authorization\Model\Acl\Loader\Role::ACL_ROLES_CACHE_KEY) + ->will( + $this->returnValue( + json_encode( + [ + [ + 'role_id' => 1, + 'role_type' => 'U', + 'parent_id' => 2, + 'user_id' => 3 + ] + ] + ) + ) + ); $this->_roleFactoryMock->expects($this->never())->method('getModelInstance'); $this->_groupFactoryMock->expects($this->never())->method('getModelInstance'); diff --git a/app/code/Magento/Authorization/Test/Unit/Model/Acl/Loader/RuleTest.php b/app/code/Magento/Authorization/Test/Unit/Model/Acl/Loader/RuleTest.php index f5f3b9b6a4b9f..2cf4b6d997fee 100644 --- a/app/code/Magento/Authorization/Test/Unit/Model/Acl/Loader/RuleTest.php +++ b/app/code/Magento/Authorization/Test/Unit/Model/Acl/Loader/RuleTest.php @@ -1,6 +1,6 @@ _resourceMock = $this->getMock( @@ -32,39 +42,71 @@ protected function setUp() false, false ); + $this->serializerMock = $this->getMock( + \Magento\Framework\Serialize\Serializer\Json::class, + ['serialize', 'unserialize'], + [], + '', + false + ); + $this->serializerMock->expects($this->any()) + ->method('serialize') + ->will( + $this->returnCallback( + function ($value) { + return json_encode($value); + } + ) + ); + + $this->serializerMock->expects($this->any()) + ->method('unserialize') + ->will( + $this->returnCallback( + function ($value) { + return json_decode($value, true); + } + ) + ); + + $this->aclDataCacheMock = $this->getMock( + \Magento\Framework\Acl\Data\CacheInterface::class, + [], + [], + '', + false + ); + $this->_rootResourceMock = new \Magento\Framework\Acl\RootResource('Magento_Backend::all'); $this->_model = new \Magento\Authorization\Model\Acl\Loader\Rule( $this->_rootResourceMock, - $this->_resourceMock + $this->_resourceMock, + [], + $this->aclDataCacheMock, + $this->serializerMock ); } - public function testPopulateAcl() + public function testPopulateAclFromCache() { - $this->_resourceMock->expects($this->any())->method('getTable')->will($this->returnArgument(1)); - - $selectMock = $this->getMock(\Magento\Framework\DB\Select::class, [], [], '', false); - $selectMock->expects($this->any())->method('from')->will($this->returnValue($selectMock)); - - $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, [], [], '', false); - $connectionMock->expects($this->once())->method('select')->will($this->returnValue($selectMock)); - $connectionMock->expects( - $this->once() - )->method( - 'fetchAll' - )->will( - $this->returnValue( - [ - ['role_id' => 1, 'resource_id' => 'Magento_Backend::all', 'permission' => 'allow'], - ['role_id' => 2, 'resource_id' => 1, 'permission' => 'allow'], - ['role_id' => 3, 'resource_id' => 1, 'permission' => 'deny'], - ] - ) - ); + $this->_resourceMock->expects($this->never())->method('getTable'); + $this->_resourceMock->expects($this->never()) + ->method('getConnection'); - $this->_resourceMock->expects($this->once()) - ->method('getConnection') - ->will($this->returnValue($connectionMock)); + $this->aclDataCacheMock->expects($this->once()) + ->method('load') + ->with(\Magento\Authorization\Model\Acl\Loader\Rule::ACL_RULE_CACHE_KEY) + ->will( + $this->returnValue( + json_encode( + [ + ['role_id' => 1, 'resource_id' => 'Magento_Backend::all', 'permission' => 'allow'], + ['role_id' => 2, 'resource_id' => 1, 'permission' => 'allow'], + ['role_id' => 3, 'resource_id' => 1, 'permission' => 'deny'], + ] + ) + ) + ); $aclMock = $this->getMock(\Magento\Framework\Acl::class); $aclMock->expects($this->any())->method('has')->will($this->returnValue(true)); diff --git a/app/code/Magento/Authorization/Test/Unit/Model/CompositeUserContextTest.php b/app/code/Magento/Authorization/Test/Unit/Model/CompositeUserContextTest.php index 3724a97a08cd2..d899194bc9e95 100644 --- a/app/code/Magento/Authorization/Test/Unit/Model/CompositeUserContextTest.php +++ b/app/code/Magento/Authorization/Test/Unit/Model/CompositeUserContextTest.php @@ -1,6 +1,6 @@ contextMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\Context::class) + ->disableOriginalConstructor() + ->setMethods(['getResources']) + ->getMock(); + + $this->resourceConnectionMock = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor() + ->setMethods(['getConnection', 'getTableName']) + ->getMock(); + + $this->contextMock->expects($this->once()) + ->method('getResources') + ->will($this->returnValue($this->resourceConnectionMock)); + + $this->connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->with('connection') + ->will($this->returnValue($this->connectionMock)); + + $this->resourceConnectionMock->expects($this->any()) + ->method('getTableName') + ->with('authorization_rule', 'connection') + ->will($this->returnArgument(0)); + + $this->aclBuilderMock = $this->getMockBuilder(\Magento\Framework\Acl\Builder::class) + ->disableOriginalConstructor() + ->setMethods(['getConfigCache']) + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->rootResourceMock = $this->getMockBuilder(\Magento\Framework\Acl\RootResource::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->aclCacheMock = $this->getMockBuilder(\Magento\Framework\Acl\CacheInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->aclDataCacheMock = $this->getMockBuilder(\Magento\Framework\Acl\Data\CacheInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->aclBuilderMock->expects($this->any()) + ->method('getConfigCache') + ->will($this->returnValue($this->aclDataCacheMock)); + + $this->ruleMock = $this->getMockBuilder(\Magento\Authorization\Model\Rules::class) + ->disableOriginalConstructor() + ->setMethods(['getRoleId']) + ->getMock(); + + $this->ruleMock->expects($this->any()) + ->method('getRoleId') + ->will($this->returnValue(self::TEST_ROLE_ID)); + + $this->model = new \Magento\Authorization\Model\ResourceModel\Rules( + $this->contextMock, + $this->aclBuilderMock, + $this->loggerMock, + $this->rootResourceMock, + $this->aclCacheMock, + 'connection', + $this->aclDataCacheMock + ); + } + + /** + * Test save with no resources posted. + */ + public function testSaveRelNoResources() + { + $this->connectionMock->expects($this->once()) + ->method('beginTransaction'); + $this->connectionMock->expects($this->once()) + ->method('delete') + ->with('authorization_rule', ['role_id = ?' => self::TEST_ROLE_ID]); + $this->connectionMock->expects($this->once()) + ->method('commit'); + + $this->aclDataCacheMock->expects($this->once()) + ->method('clean'); + + $this->model->saveRel($this->ruleMock); + } + + /** + * Test LocalizedException throw case. + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage TestException + */ + public function testLocalizedExceptionOccurance() + { + $exceptionPhrase = $this->getMockBuilder(\Magento\Framework\Phrase::class) + ->disableOriginalConstructor() + ->setMethods(['render']) + ->getMock(); + + $exceptionPhrase->expects($this->any())->method('render')->will($this->returnValue('TestException')); + + $exception = new \Magento\Framework\Exception\LocalizedException($exceptionPhrase); + + $this->connectionMock->expects($this->once()) + ->method('beginTransaction'); + + $this->connectionMock->expects($this->once()) + ->method('delete') + ->with('authorization_rule', ['role_id = ?' => self::TEST_ROLE_ID]) + ->will($this->throwException($exception)); + + $this->connectionMock->expects($this->once())->method('rollBack'); + + $this->model->saveRel($this->ruleMock); + } + + /** + * Test generic exception throw case. + */ + public function testGenericExceptionOccurance() + { + $exception = new \Exception('GenericException'); + + $this->connectionMock->expects($this->once()) + ->method('beginTransaction'); + + $this->connectionMock->expects($this->once()) + ->method('delete') + ->with('authorization_rule', ['role_id = ?' => self::TEST_ROLE_ID]) + ->will($this->throwException($exception)); + + $this->connectionMock->expects($this->once())->method('rollBack'); + $this->loggerMock->expects($this->once())->method('critical')->with($exception); + + $this->model->saveRel($this->ruleMock); + } +} diff --git a/app/code/Magento/Authorization/composer.json b/app/code/Magento/Authorization/composer.json index 0ca367d4854df..af88e8376dc75 100644 --- a/app/code/Magento/Authorization/composer.json +++ b/app/code/Magento/Authorization/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-authorization", "description": "Authorization module provides access to Magento ACL functionality.", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/module-backend": "100.2.*", "magento/framework": "100.2.*" }, diff --git a/app/code/Magento/Authorization/etc/di.xml b/app/code/Magento/Authorization/etc/di.xml index 1159fb0a7606e..9370e14d81a35 100644 --- a/app/code/Magento/Authorization/etc/di.xml +++ b/app/code/Magento/Authorization/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorization/etc/module.xml b/app/code/Magento/Authorization/etc/module.xml index f3fa8793f3e57..f27253870499d 100644 --- a/app/code/Magento/Authorization/etc/module.xml +++ b/app/code/Magento/Authorization/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorization/registration.php b/app/code/Magento/Authorization/registration.php index 6aabf5a16bb91..f35b17a4d6710 100644 --- a/app/code/Magento/Authorization/registration.php +++ b/app/code/Magento/Authorization/registration.php @@ -1,6 +1,6 @@ dataFactory->create($area); $params = []; - $data = $this->getRequest()->getPostValue(); + $data = $this->getRequest()->getParams(); + /* @var $paymentMethod \Magento\Authorizenet\Model\DirectPost */ $paymentMethod = $this->_objectManager->create(\Magento\Authorizenet\Model\Directpost::class); @@ -110,9 +111,8 @@ protected function _responseAction($area = 'frontend') $params['redirect'] = $helper->getRedirectIframeUrl($result); } + //registering parameter for iframe content $this->_coreRegistry->register(Iframe::REGISTRY_KEY, $params); - $this->_view->addPageLayoutHandles(); - $this->_view->loadLayout(false)->renderLayout(); } /** diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php index c0ac07a11adb3..6e2401d930b16 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/BackendResponse.php @@ -1,7 +1,7 @@ _responseAction('adminhtml'); + return $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_PAGE); } } diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php index 2816a3bae78b9..0921c9bb4d0c6 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/Place.php @@ -1,6 +1,6 @@ _responseAction('frontend'); + return $this->resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_PAGE); } } diff --git a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php index 5bfe916160967..c542c16e9fa7e 100644 --- a/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php +++ b/app/code/Magento/Authorizenet/Controller/Directpost/Payment/ReturnQuote.php @@ -1,7 +1,7 @@ setXCity($billing->getCity()) ->setXState($billing->getRegion()) ->setXZip($billing->getPostcode()) - ->setXCountry($billing->getCountry()) + ->setXCountry($billing->getCountryId()) ->setXPhone($billing->getTelephone()) ->setXFax($billing->getFax()) ->setXCustId($order->getCustomerId()) @@ -352,7 +352,7 @@ protected function buildRequest(\Magento\Framework\DataObject $payment) ->setXShipToCity($shipping->getCity()) ->setXShipToState($shipping->getRegion()) ->setXShipToZip($shipping->getPostcode()) - ->setXShipToCountry($shipping->getCountry()); + ->setXShipToCountry($shipping->getCountryId()); } $request->setXPoNum($payment->getPoNumber()) diff --git a/app/code/Magento/Authorizenet/Model/Debug.php b/app/code/Magento/Authorizenet/Model/Debug.php index 3e46731197660..7605aa762a183 100644 --- a/app/code/Magento/Authorizenet/Model/Debug.php +++ b/app/code/Magento/Authorizenet/Model/Debug.php @@ -1,6 +1,6 @@ setXCity(strval($billing->getCity())) ->setXState(strval($billing->getRegion())) ->setXZip(strval($billing->getPostcode())) - ->setXCountry(strval($billing->getCountry())) + ->setXCountry(strval($billing->getCountryId())) ->setXPhone(strval($billing->getTelephone())) ->setXFax(strval($billing->getFax())) ->setXCustId(strval($billing->getCustomerId())) @@ -151,7 +151,7 @@ public function setDataFromOrder( )->setXShipToZip( strval($shipping->getPostcode()) )->setXShipToCountry( - strval($shipping->getCountry()) + strval($shipping->getCountryId()) ); } diff --git a/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php b/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php index 7ef6647285616..d0f6ea6515d11 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php +++ b/app/code/Magento/Authorizenet/Model/Directpost/Request/Factory.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Authorizenet/etc/adminhtml/events.xml b/app/code/Magento/Authorizenet/etc/adminhtml/events.xml index 4a669cd7d9cac..8114b8c8312cc 100644 --- a/app/code/Magento/Authorizenet/etc/adminhtml/events.xml +++ b/app/code/Magento/Authorizenet/etc/adminhtml/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/etc/adminhtml/routes.xml b/app/code/Magento/Authorizenet/etc/adminhtml/routes.xml index ef3e63f2c9c90..028e1a8500d07 100644 --- a/app/code/Magento/Authorizenet/etc/adminhtml/routes.xml +++ b/app/code/Magento/Authorizenet/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/etc/adminhtml/system.xml b/app/code/Magento/Authorizenet/etc/adminhtml/system.xml index fd2fb84f0a290..3d4cde185dcd1 100644 --- a/app/code/Magento/Authorizenet/etc/adminhtml/system.xml +++ b/app/code/Magento/Authorizenet/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/etc/config.xml b/app/code/Magento/Authorizenet/etc/config.xml index 70b413b5c1a39..f5b053003f1f2 100644 --- a/app/code/Magento/Authorizenet/etc/config.xml +++ b/app/code/Magento/Authorizenet/etc/config.xml @@ -1,7 +1,7 @@ @@ -10,7 +10,7 @@ 0 - AE,VI,MC,DI + AE,VI,MC,DI,JCB,DN 0 0 diff --git a/app/code/Magento/Authorizenet/etc/di.xml b/app/code/Magento/Authorizenet/etc/di.xml index f5e595fb450e8..3bd70f25a3bf9 100644 --- a/app/code/Magento/Authorizenet/etc/di.xml +++ b/app/code/Magento/Authorizenet/etc/di.xml @@ -1,7 +1,7 @@ @@ -16,4 +16,14 @@ Magento\Authorizenet\Model\Directpost\Session\Storage + + + + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Authorizenet/etc/frontend/di.xml b/app/code/Magento/Authorizenet/etc/frontend/di.xml index 7f20e067cc426..8dcf8ed700dcb 100644 --- a/app/code/Magento/Authorizenet/etc/frontend/di.xml +++ b/app/code/Magento/Authorizenet/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/etc/frontend/events.xml b/app/code/Magento/Authorizenet/etc/frontend/events.xml index bb11f4bca363a..2c6e3f12a9196 100644 --- a/app/code/Magento/Authorizenet/etc/frontend/events.xml +++ b/app/code/Magento/Authorizenet/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/etc/frontend/page_types.xml b/app/code/Magento/Authorizenet/etc/frontend/page_types.xml index 6dc50d5d28dd9..be4692b135955 100644 --- a/app/code/Magento/Authorizenet/etc/frontend/page_types.xml +++ b/app/code/Magento/Authorizenet/etc/frontend/page_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/etc/frontend/routes.xml b/app/code/Magento/Authorizenet/etc/frontend/routes.xml index 7da347a2e6381..1bdcff9f1efe1 100644 --- a/app/code/Magento/Authorizenet/etc/frontend/routes.xml +++ b/app/code/Magento/Authorizenet/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Authorizenet/etc/frontend/sections.xml b/app/code/Magento/Authorizenet/etc/frontend/sections.xml index 33c48e60e8dab..977a4b14e3e14 100644 --- a/app/code/Magento/Authorizenet/etc/frontend/sections.xml +++ b/app/code/Magento/Authorizenet/etc/frontend/sections.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/etc/module.xml b/app/code/Magento/Authorizenet/etc/module.xml index 75317e254efaa..91d93e56e0cad 100644 --- a/app/code/Magento/Authorizenet/etc/module.xml +++ b/app/code/Magento/Authorizenet/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/i18n/en_US.csv b/app/code/Magento/Authorizenet/i18n/en_US.csv index 7183c706dc0a2..45025304c4e44 100644 --- a/app/code/Magento/Authorizenet/i18n/en_US.csv +++ b/app/code/Magento/Authorizenet/i18n/en_US.csv @@ -64,3 +64,4 @@ Debug,Debug "Minimum Order Total","Minimum Order Total" "Maximum Order Total","Maximum Order Total" "Sort Order","Sort Order" +"Sorry, but something went wrong. Please contact the seller.","Sorry, but something went wrong. Please contact the seller." diff --git a/app/code/Magento/Authorizenet/registration.php b/app/code/Magento/Authorizenet/registration.php index a0eab4323313e..ad98beafa744d 100644 --- a/app/code/Magento/Authorizenet/registration.php +++ b/app/code/Magento/Authorizenet/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_index.xml index aeed400c3c8fa..851cbf398750d 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_index.xml +++ b/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_index.xml @@ -1,7 +1,7 @@ @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml b/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml index 21e8f1d70fbb5..ec5ce845b8521 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml +++ b/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml @@ -1,7 +1,7 @@ @@ -14,4 +14,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_view.xml b/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_view.xml index d81573c891c9f..7470afcfdb7d0 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_view.xml +++ b/app/code/Magento/Authorizenet/view/adminhtml/layout/sales_order_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/iframe.phtml b/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/iframe.phtml index ae5a5ec6217ed..2b95af46a6b47 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/iframe.phtml +++ b/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/iframe.phtml @@ -1,6 +1,6 @@ getInfoData('cc_exp_year');
+
-
-
+ +
@@ -66,7 +76,11 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
+ hasVerification()): ?> -
-
- \ No newline at end of file + diff --git a/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js b/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js index 69dd63cf47caa..ec0701da0da38 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js +++ b/app/code/Magento/Authorizenet/view/adminhtml/web/js/direct-post.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ (function (factory) { diff --git a/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_backendresponse.xml b/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_backendresponse.xml index 97f425e78c7de..1eedd5e26a3ed 100644 --- a/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_backendresponse.xml +++ b/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_backendresponse.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_redirect.xml b/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_redirect.xml index 97f425e78c7de..1eedd5e26a3ed 100644 --- a/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_redirect.xml +++ b/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_redirect.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_response.xml b/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_response.xml index 97f425e78c7de..1eedd5e26a3ed 100644 --- a/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_response.xml +++ b/app/code/Magento/Authorizenet/view/frontend/layout/authorizenet_directpost_payment_response.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Authorizenet/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Authorizenet/view/frontend/layout/checkout_index_index.xml index 489dddc9b15d6..1025207fec1d5 100644 --- a/app/code/Magento/Authorizenet/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Authorizenet/view/frontend/layout/checkout_index_index.xml @@ -1,7 +1,7 @@ @@ -46,4 +46,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js b/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js index 4af97d5775a7f..26c0e732303d0 100644 --- a/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js +++ b/app/code/Magento/Authorizenet/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/authorizenet.js b/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/authorizenet.js index 83b3984735563..6f7f94eab63fc 100644 --- a/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/authorizenet.js +++ b/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/authorizenet.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*browser:true*/ @@ -23,4 +23,4 @@ define( /** Add view logic here if needed */ return Component.extend({}); } -); \ No newline at end of file +); diff --git a/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js b/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js index cd05960c17633..a40f3e9276712 100644 --- a/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js +++ b/app/code/Magento/Authorizenet/view/frontend/web/js/view/payment/method-renderer/authorizenet-directpost.js @@ -1,19 +1,20 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define( [ 'jquery', - 'Magento_Payment/js/view/payment/iframe' + 'Magento_Payment/js/view/payment/iframe', + 'mage/translate' ], - function ($, Component) { + function ($, Component, $t) { 'use strict'; return Component.extend({ defaults: { template: 'Magento_Authorizenet/payment/authorizenet-directpost', - timeoutMessage: 'Sorry, but something went wrong. Please contact the seller.' + timeoutMessage: $t('Sorry, but something went wrong. Please contact the seller.') }, placeOrderHandler: null, validateHandler: null, diff --git a/app/code/Magento/Authorizenet/view/frontend/web/template/payment/authorizenet-directpost.html b/app/code/Magento/Authorizenet/view/frontend/web/template/payment/authorizenet-directpost.html index 1aff94817c6eb..2de6cad54d267 100644 --- a/app/code/Magento/Authorizenet/view/frontend/web/template/payment/authorizenet-directpost.html +++ b/app/code/Magento/Authorizenet/view/frontend/web/template/payment/authorizenet-directpost.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/App/AbstractAction.php b/app/code/Magento/Backend/App/AbstractAction.php index f0973b8f66a65..4efd013f43a1c 100644 --- a/app/code/Magento/Backend/App/AbstractAction.php +++ b/app/code/Magento/Backend/App/AbstractAction.php @@ -1,6 +1,6 @@ _scopePool = $scopePool; + $this->appConfig = $appConfig; } /** - * Retrieve config value by path and scope - * - * @param string $path - * @return mixed + * @inheritdoc */ public function getValue($path) { - return $this->_scopePool->getScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null)->getValue($path); + if (isset($this->data[$path])) { + return $this->data[$path]; + } + + $configPath = ScopeConfigInterface::SCOPE_TYPE_DEFAULT; + if ($path) { + $configPath .= '/' . $path; + } + return $this->appConfig->get(System::CONFIG_TYPE, $configPath); } /** - * Set config value in the corresponding config scope - * - * @param string $path - * @param mixed $value - * @return void + * @inheritdoc */ public function setValue($path, $value) { - $this->_scopePool->getScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null)->setValue($path, $value); + $this->data[$path] = $value; } /** - * Retrieve config flag - * - * @param string $path - * @return bool + * @inheritdoc */ public function isSetFlag($path) { - return !!$this->_scopePool->getScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null)->getValue($path); + $configPath = ScopeConfigInterface::SCOPE_TYPE_DEFAULT; + if ($path) { + $configPath .= '/' . $path; + } + return (bool) $this->appConfig->get(System::CONFIG_TYPE, $configPath); } } diff --git a/app/code/Magento/Backend/App/ConfigInterface.php b/app/code/Magento/Backend/App/ConfigInterface.php index 4000b54cc9834..1e183bc8fd1bd 100644 --- a/app/code/Magento/Backend/App/ConfigInterface.php +++ b/app/code/Magento/Backend/App/ConfigInterface.php @@ -2,7 +2,7 @@ /** * Default application path for backend area * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Backend\App; @@ -15,6 +15,8 @@ interface ConfigInterface /** * Retrieve config value by path * + * Path should looks like keys imploded by "/". For example scopes/stores/admin + * * @param string $path * @return mixed * @api @@ -24,6 +26,7 @@ public function getValue($path); /** * Set config value * + * @deprecated * @param string $path * @param mixed $value * @return void @@ -34,6 +37,8 @@ public function setValue($path, $value); /** * Retrieve config flag * + * Path should looks like keys imploded by "/". For example scopes/stores/admin + * * @param string $path * @return bool * @api diff --git a/app/code/Magento/Backend/App/DefaultPath.php b/app/code/Magento/Backend/App/DefaultPath.php index ef3d502db8ab8..9a25e328bde52 100644 --- a/app/code/Magento/Backend/App/DefaultPath.php +++ b/app/code/Magento/Backend/App/DefaultPath.php @@ -2,7 +2,7 @@ /** * Default application path for backend area * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Backend\App; diff --git a/app/code/Magento/Backend/App/Request/PathInfoProcessor.php b/app/code/Magento/Backend/App/Request/PathInfoProcessor.php index 08e115e9ec795..e0890ce917897 100644 --- a/app/code/Magento/Backend/App/Request/PathInfoProcessor.php +++ b/app/code/Magento/Backend/App/Request/PathInfoProcessor.php @@ -2,7 +2,7 @@ /** * Prevents path info processing for admin store * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Backend\App\Request; diff --git a/app/code/Magento/Backend/App/Response/Http/FileFactory.php b/app/code/Magento/Backend/App/Response/Http/FileFactory.php index dec52cdb646b0..1c67275a7fc67 100644 --- a/app/code/Magento/Backend/App/Response/Http/FileFactory.php +++ b/app/code/Magento/Backend/App/Response/Http/FileFactory.php @@ -1,6 +1,6 @@ menuItemChecker = $menuItemChecker; + $this->escaper = $escaper; + } + + /** + * Render menu item anchor. + * + * It is used in backend menu to render anchor menu. + * + * @param Item|false $activeItem Can be false if menu item is inaccessible + * but was triggered directly using controller. It is a legacy code behaviour. + * @param Item $menuItem + * @param int $level + * @return string + */ + public function renderAnchor($activeItem, Item $menuItem, $level) + { + if ($level == 1 && $menuItem->getUrl() == '#') { + $output = '' + . '' . $this->escaper->escapeHtml(__($menuItem->getTitle())) . '' + . ''; + } else { + $target = $menuItem->getTarget() ? ('target=' . $menuItem->getTarget()) : ''; + $output = '_renderItemAnchorTitle( + $menuItem + ) . $this->_renderItemOnclickFunction( + $menuItem + ) . ' class="' . ($this->menuItemChecker->isItemActive($activeItem, $menuItem, $level) ? '_active' : '') + . '">' . '' . $this->escaper->escapeHtml(__($menuItem->getTitle())) + . '' . ''; + } + + return $output; + } + + /** + * Render menu item anchor title + * + * @param Item $menuItem + * @return string + */ + private function _renderItemAnchorTitle($menuItem) + { + return $menuItem->hasTooltip() ? 'title="' . __($menuItem->getTooltip()) . '"' : ''; + } + + /** + * Render menu item onclick function + * + * @param Item $menuItem + * @return string + */ + private function _renderItemOnclickFunction($menuItem) + { + return $menuItem->hasClickCallback() ? ' onclick="' . $menuItem->getClickCallback() . '"' : ''; + } +} diff --git a/app/code/Magento/Backend/Block/Cache.php b/app/code/Magento/Backend/Block/Cache.php index 8b53882274182..b9a11fa5bb543 100644 --- a/app/code/Magento/Backend/Block/Cache.php +++ b/app/code/Magento/Backend/Block/Cache.php @@ -1,6 +1,6 @@ state = $state; + } + + /** + * {@inheritdoc} + */ + public function isVisible() + { + return $this->state->getMode() !== State::MODE_PRODUCTION; + } +} diff --git a/app/code/Magento/Backend/Block/Catalog/Product/Tab/Container.php b/app/code/Magento/Backend/Block/Catalog/Product/Tab/Container.php index bed5ee24434d9..49107a0ae4f7f 100644 --- a/app/code/Magento/Backend/Block/Catalog/Product/Tab/Container.php +++ b/app/code/Magento/Backend/Block/Catalog/Product/Tab/Container.php @@ -1,6 +1,6 @@ _url = $url; $this->_iteratorFactory = $iteratorFactory; $this->_authSession = $authSession; $this->_menuConfig = $menuConfig; $this->_localeResolver = $localeResolver; + $this->menuItemChecker = $menuItemChecker; + $this->anchorRenderer = $anchorRenderer; parent::__construct($context, $data); } @@ -99,30 +115,6 @@ protected function _construct() $this->setCacheTags([self::CACHE_TAGS]); } - /** - * Check whether given item is currently selected - * - * @param \Magento\Backend\Model\Menu\Item $item - * @param int $level - * @return bool - */ - protected function _isItemActive(\Magento\Backend\Model\Menu\Item $item, $level) - { - $itemModel = $this->getActiveItemModel(); - $output = false; - - if ($level == 0 && - $itemModel instanceof \Magento\Backend\Model\Menu\Item && - ($itemModel->getId() == $item->getId() || - $item->getChildren()->get( - $itemModel->getId() - ) !== null) - ) { - $output = true; - } - return $output; - } - /** * Render menu item anchor label * @@ -134,40 +126,6 @@ protected function _getAnchorLabel($menuItem) return $this->escapeHtml(__($menuItem->getTitle())); } - /** - * Render menu item anchor title - * - * @param \Magento\Backend\Model\Menu\Item $menuItem - * @return string - */ - protected function _renderItemAnchorTitle($menuItem) - { - return $menuItem->hasTooltip() ? 'title="' . __($menuItem->getTooltip()) . '"' : ''; - } - - /** - * Render menu item onclick function - * - * @param \Magento\Backend\Model\Menu\Item $menuItem - * @return string - */ - protected function _renderItemOnclickFunction($menuItem) - { - return $menuItem->hasClickCallback() ? ' onclick="' . $menuItem->getClickCallback() . '"' : ''; - } - - /** - * Render menu item anchor css class - * - * @param \Magento\Backend\Model\Menu\Item $menuItem - * @param int $level - * @return string - */ - protected function _renderAnchorCssClass($menuItem, $level) - { - return $this->_isItemActive($menuItem, $level) ? '_active' : ''; - } - /** * Render menu item mouse events * @param \Magento\Backend\Model\Menu\Item $menuItem @@ -188,10 +146,11 @@ protected function _renderMouseEvent($menuItem) protected function _renderItemCssClass($menuItem, $level) { $isLast = 0 == $level && (bool)$this->getMenuModel()->isLast($menuItem) ? 'last' : ''; - $output = ($this->_isItemActive( - $menuItem, - $level - ) ? '_current _active' : '') . + $output = ($this->menuItemChecker->isItemActive( + $this->getActiveItemModel(), + $menuItem, + $level + ) ? '_current _active' : '') . ' ' . ($menuItem->hasChildren() ? 'parent' : '') . ' ' . @@ -202,34 +161,6 @@ protected function _renderItemCssClass($menuItem, $level) return $output; } - /** - * Render menu item anchor - * @param \Magento\Backend\Model\Menu\Item $menuItem - * @param int $level - * @return string - */ - protected function _renderAnchor($menuItem, $level) - { - if ($level == 1 && $menuItem->getUrl() == '#') { - $output = '' - . '' . $this->_getAnchorLabel($menuItem) . '' - . ''; - } else { - $output = '_renderItemAnchorTitle( - $menuItem - ) . $this->_renderItemOnclickFunction( - $menuItem - ) . ' class="' . $this->_renderAnchorCssClass( - $menuItem, - $level - ) . '">' . '' . $this->_getAnchorLabel( - $menuItem - ) . '' . ''; - } - - return $output; - } - /** * Get menu filter iterator * @@ -336,7 +267,7 @@ public function renderMenu($menu, $level = 0) $menuItem->getId() ) . 'role="menuitem">'; - $output .= $this->_renderAnchor($menuItem, $level); + $output .= $this->anchorRenderer->renderAnchor($this->getActiveItemModel(), $menuItem, $level); if ($menuItem->hasChildren()) { $output .= $this->renderMenu($menuItem->getChildren(), $level + 1); @@ -456,7 +387,7 @@ public function renderNavigation($menu, $level = 0, $limit = 0, $colBrakes = []) $id = $this->getJsId($menuItem->getId()); $subMenu = $this->_addSubMenu($menuItem, $level, $limit, $id); - $anchor = $this->_renderAnchor($menuItem, $level); + $anchor = $this->anchorRenderer->renderAnchor($this->getActiveItemModel(), $menuItem, $level); $output .= '
  • getUiId($menuItem->getId()) . ' class="item-' . $itemClass . ' ' . $this->_renderItemCssClass($menuItem, $level) . ($level == 0 ? '" id="' . $id . '" aria-haspopup="true' : '') @@ -474,7 +405,7 @@ public function renderNavigation($menu, $level = 0, $limit = 0, $colBrakes = []) /** * Get current selected menu item * - * @return \Magento\Backend\Model\Menu\Item|null|bool + * @return \Magento\Backend\Model\Menu\Item|false */ public function getActiveItemModel() { diff --git a/app/code/Magento/Backend/Block/MenuItemChecker.php b/app/code/Magento/Backend/Block/MenuItemChecker.php new file mode 100644 index 0000000000000..b85b060cd379d --- /dev/null +++ b/app/code/Magento/Backend/Block/MenuItemChecker.php @@ -0,0 +1,49 @@ +isActiveItemEqualOrChild($activeItem, $item) + ) { + $output = true; + } + return $output; + } + + /** + * @param Item $activeItem, + * @param Item $item + * @return bool + */ + private function isActiveItemEqualOrChild($activeItem, $item) + { + return ($activeItem->getId() == $item->getId()) + || ($item->getChildren()->get($activeItem->getId()) !== null); + } +} diff --git a/app/code/Magento/Backend/Block/Page.php b/app/code/Magento/Backend/Block/Page.php index dca6a97a588c1..750eaebf58de6 100644 --- a/app/code/Magento/Backend/Block/Page.php +++ b/app/code/Magento/Backend/Block/Page.php @@ -1,6 +1,6 @@ _storeManager->getWebsites(); if ($websiteIds = $this->getWebsiteIds()) { - foreach (array_keys($websites) as $websiteId) { - if (!in_array($websiteId, $websiteIds)) { - unset($websites[$websiteId]); - } - } + $websites = array_intersect_key($websites, array_flip($websiteIds)); } return $websites; } diff --git a/app/code/Magento/Backend/Block/Store/Switcher/Form/Renderer/Fieldset.php b/app/code/Magento/Backend/Block/Store/Switcher/Form/Renderer/Fieldset.php index 248031dc76262..b8c1b7d9e1068 100644 --- a/app/code/Magento/Backend/Block/Store/Switcher/Form/Renderer/Fieldset.php +++ b/app/code/Magento/Backend/Block/Store/Switcher/Form/Renderer/Fieldset.php @@ -1,6 +1,6 @@ getModuleName(); - } - - return !$this->_scopeConfig->isSetFlag( - 'advanced/modules_disable_output/' . $moduleName, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); + return true; } /** diff --git a/app/code/Magento/Backend/Block/Template/Context.php b/app/code/Magento/Backend/Block/Template/Context.php index 2cebd1cd5e49e..4f1324763f351 100644 --- a/app/code/Magento/Backend/Block/Template/Context.php +++ b/app/code/Magento/Backend/Block/Template/Context.php @@ -2,7 +2,7 @@ /** * Backend block template context * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Backend/Block/Text/ListText.php b/app/code/Magento/Backend/Block/Text/ListText.php index 3ec68b25707b3..0dd8d0c05ac53 100644 --- a/app/code/Magento/Backend/Block/Text/ListText.php +++ b/app/code/Magento/Backend/Block/Text/ListText.php @@ -1,6 +1,6 @@ hasData(self::PARAM_BLOCK_GROUP)) { + $this->_blockGroup = $this->_getData(self::PARAM_BLOCK_GROUP); + } + if ($this->hasData(self::PARAM_MODE)) { + $this->_mode = $this->_getData(self::PARAM_MODE); + } $this->addButton( 'back', diff --git a/app/code/Magento/Backend/Block/Widget/Form/Element.php b/app/code/Magento/Backend/Block/Widget/Form/Element.php index cc701fc9dd34b..ac19ef6d2b9b6 100644 --- a/app/code/Magento/Backend/Block/Widget/Form/Element.php +++ b/app/code/Magento/Backend/Block/Widget/Form/Element.php @@ -1,6 +1,6 @@ */ -namespace Magento\Backend\Block\Widget\Grid\Column\Renderer; - class Text extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer { /** @@ -21,30 +20,53 @@ class Text extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRe protected $_variablePattern = '/\\$([a-z0-9_]+)/i'; /** - * Renders grid column + * Get value for the cel * - * @param \Magento\Framework\DataObject $row - * @return mixed + * @param DataObject $row + * @return string */ - public function _getValue(\Magento\Framework\DataObject $row) + public function _getValue(DataObject $row) { - $format = $this->getColumn()->getFormat() ? $this->getColumn()->getFormat() : null; - $defaultValue = $this->getColumn()->getDefault(); - if ($format === null) { - // If no format and it column not filtered specified return data as is. - $data = parent::_getValue($row); - $string = $data === null ? $defaultValue : $data; - return $this->escapeHtml($string); - } elseif (preg_match_all($this->_variablePattern, $format, $matches)) { - // Parsing of format string - $formattedString = $format; - foreach ($matches[0] as $matchIndex => $match) { - $value = $row->getData($matches[1][$matchIndex]); - $formattedString = str_replace($match, $value, $formattedString); + if (null === $this->getColumn()->getFormat()) { + return $this->getSimpleValue($row); + } + return $this->getFormattedValue($row); + } + + /** + * Get simple value + * + * @param DataObject $row + * @return string + */ + private function getSimpleValue(DataObject $row) + { + $data = parent::_getValue($row); + $value = null === $data ? $this->getColumn()->getDefault() : $data; + if (true === $this->getColumn()->getTranslate()) { + $value = __($value); + } + return $this->escapeHtml($value); + } + + /** + * Replace placeholders in the string with values + * + * @param DataObject $row + * @return string + */ + private function getFormattedValue(DataObject $row) + { + $value = $this->getColumn()->getFormat() ?: null; + if (true === $this->getColumn()->getTranslate()) { + $value = __($value); + } + if (preg_match_all($this->_variablePattern, $value, $matches)) { + foreach ($matches[0] as $index => $match) { + $replacement = $row->getData($matches[1][$index]); + $value = str_replace($match, $replacement, $value); } - return $formattedString; - } else { - return $this->escapeHtml($format); } + return $this->escapeHtml($value); } } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Wrapline.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Wrapline.php index a45584438af5e..b11d14be78f98 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Wrapline.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Renderer/Wrapline.php @@ -1,6 +1,6 @@ */ -namespace Magento\Backend\Block\Widget\Grid; - class Massaction extends \Magento\Backend\Block\Widget\Grid\Massaction\AbstractMassaction { } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php index 2f3df1377b395..380b2991eb0d9 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/AbstractMassaction.php @@ -1,18 +1,18 @@ */ abstract class AbstractMassaction extends \Magento\Backend\Block\Widget { @@ -73,20 +73,21 @@ protected function _construct() * 'complete' => string, // Only for ajax enabled grid (optional) * 'url' => string, * 'confirm' => string, // text of confirmation of this action (optional) - * 'additional' => string // (optional) + * 'additional' => string, // (optional) + * 'visible' => object // instance of VisibilityCheckerInterface (optional) * ); * * @param string $itemId - * @param array|\Magento\Framework\DataObject $item + * @param array|DataObject $item * @return $this */ public function addItem($itemId, $item) { if (is_array($item)) { - $item = new \Magento\Framework\DataObject($item); + $item = new DataObject($item); } - if ($item instanceof \Magento\Framework\DataObject) { + if ($item instanceof DataObject && $this->isVisible($item)) { $item->setId($itemId); $item->setUrl($this->getUrl($item->getUrl())); $this->_items[$itemId] = $item; @@ -95,6 +96,19 @@ public function addItem($itemId, $item) return $this; } + /** + * Check that item can be added to list + * + * @param DataObject $item + * @return bool + */ + private function isVisible(DataObject $item) + { + /** @var VisibilityChecker $checker */ + $checker = $item->getData('visible'); + return (!$checker instanceof VisibilityChecker) || $checker->isVisible(); + } + /** * Retrieve massaction item with id $itemId * diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Additional.php b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Additional.php index 898e2efb508bd..15250b3904d2d 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Additional.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Massaction/Additional.php @@ -1,6 +1,6 @@ getState()->getMode() === State::MODE_PRODUCTION) { + $this->messageManager->addErrorMessage(__('You can\'t change status of cache type(s) in production mode')); + } else { + $this->disableCache(); + } + + return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('adminhtml/*'); + } + + /** + * Disable cache + * + * @return void + */ + private function disableCache() { try { $types = $this->getRequest()->getParam('types'); @@ -41,9 +67,20 @@ public function execute() } catch (\Exception $e) { $this->messageManager->addException($e, __('An error occurred while disabling cache.')); } + } + + /** + * Get State Instance + * + * @return State + * @deprecated + */ + private function getState() + { + if ($this->state === null) { + $this->state = ObjectManager::getInstance()->get(State::class); + } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); - return $resultRedirect->setPath('adminhtml/*'); + return $this->state; } } diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php index 6c8bccfee166a..0cf09508c2932 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassEnable.php @@ -1,22 +1,48 @@ getState()->getMode() === State::MODE_PRODUCTION) { + $this->messageManager->addErrorMessage(__('You can\'t change status of cache type(s) in production mode')); + } else { + $this->enableCache(); + } + + return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('adminhtml/*'); + } + + /** + * Enable cache + * + * @return void + */ + private function enableCache() { try { $types = $this->getRequest()->getParam('types'); @@ -40,9 +66,20 @@ public function execute() } catch (\Exception $e) { $this->messageManager->addException($e, __('An error occurred while enabling cache.')); } + } + + /** + * Get State Instance + * + * @return State + * @deprecated + */ + private function getState() + { + if ($this->state === null) { + $this->state = ObjectManager::getInstance()->get(State::class); + } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); - return $resultRedirect->setPath('adminhtml/*'); + return $this->state; } } diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php index 83ea91e32bf8c..ed546ba91adec 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/Cache/MassRefresh.php @@ -1,7 +1,7 @@ resultPageFactory->create(); + /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ + $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE); + $resultPage->setActiveMenu('Magento_Backend::system_store'); + $resultPage->addBreadcrumb(__('Stores'), __('Stores')); + $resultPage->addBreadcrumb(__('All Stores'), __('All Stores')); $resultPage->getConfig()->getTitle()->prepend(__('Stores')); - return $resultPage; } } diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/NewGroup.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/NewGroup.php index c9d46a1a779b4..40dd82dd8cd4b 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/NewGroup.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/NewGroup.php @@ -1,7 +1,7 @@ filterManager->removeTags($postData['website']['name']); + $websiteModel = $this->_objectManager->create(\Magento\Store\Model\Website::class); + if ($postData['website']['website_id']) { + $websiteModel->load($postData['website']['website_id']); + } + $websiteModel->setData($postData['website']); + if ($postData['website']['website_id'] == '') { + $websiteModel->setId(null); + } + + $websiteModel->save(); + $this->messageManager->addSuccess(__('You saved the website.')); + + return $postData; + } + + /** + * Process Store model save + * + * @param array $postData + * @throws \Magento\Framework\Exception\LocalizedException + * @return array + */ + private function processStoreSave($postData) + { + $eventName = 'store_edit'; + /** @var \Magento\Store\Model\Store $storeModel */ + $storeModel = $this->_objectManager->create(\Magento\Store\Model\Store::class); + $postData['store']['name'] = $this->filterManager->removeTags($postData['store']['name']); + if ($postData['store']['store_id']) { + $storeModel->load($postData['store']['store_id']); + } + $storeModel->setData($postData['store']); + if ($postData['store']['store_id'] == '') { + $storeModel->setId(null); + $eventName = 'store_add'; + } + $groupModel = $this->_objectManager->create( + \Magento\Store\Model\Group::class + )->load( + $storeModel->getGroupId() + ); + $storeModel->setWebsiteId($groupModel->getWebsiteId()); + if (!$storeModel->isActive() && $storeModel->isDefault()) { + throw new \Magento\Framework\Exception\LocalizedException( + __('The default store cannot be disabled') + ); + } + $storeModel->save(); + $this->_objectManager->get(\Magento\Store\Model\StoreManager::class)->reinitStores(); + $this->_eventManager->dispatch($eventName, ['store' => $storeModel]); + $this->messageManager->addSuccess(__('You saved the store view.')); + + return $postData; + } + + /** + * Process StoreGroup model save + * + * @param array $postData + * @throws \Magento\Framework\Exception\LocalizedException + * @return array + */ + private function processGroupSave($postData) + { + $postData['group']['name'] = $this->filterManager->removeTags($postData['group']['name']); + /** @var \Magento\Store\Model\Group $groupModel */ + $groupModel = $this->_objectManager->create(\Magento\Store\Model\Group::class); + if ($postData['group']['group_id']) { + $groupModel->load($postData['group']['group_id']); + } + $groupModel->setData($postData['group']); + if ($postData['group']['group_id'] == '') { + $groupModel->setId(null); + } + if (!$this->isSelectedDefaultStoreActive($postData, $groupModel)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('An inactive store view cannot be saved as default store view') + ); + } + $groupModel->save(); + $this->_eventManager->dispatch('store_group_save', ['group' => $groupModel]); + $this->messageManager->addSuccess(__('You saved the store.')); + + return $postData; + } + /** * @return \Magento\Backend\Model\View\Result\Redirect * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -22,73 +121,16 @@ public function execute() $redirectResult->setPath('adminhtml/*/'); return $redirectResult; } - try { switch ($postData['store_type']) { case 'website': - $postData['website']['name'] = $this->filterManager->removeTags($postData['website']['name']); - $websiteModel = $this->_objectManager->create(\Magento\Store\Model\Website::class); - if ($postData['website']['website_id']) { - $websiteModel->load($postData['website']['website_id']); - } - $websiteModel->setData($postData['website']); - if ($postData['website']['website_id'] == '') { - $websiteModel->setId(null); - } - - $websiteModel->save(); - $this->messageManager->addSuccess(__('You saved the website.')); + $postData = $this->processWebsiteSave($postData); break; - case 'group': - $postData['group']['name'] = $this->filterManager->removeTags($postData['group']['name']); - /** @var \Magento\Store\Model\Group $groupModel */ - $groupModel = $this->_objectManager->create(\Magento\Store\Model\Group::class); - if ($postData['group']['group_id']) { - $groupModel->load($postData['group']['group_id']); - } - $groupModel->setData($postData['group']); - if ($postData['group']['group_id'] == '') { - $groupModel->setId(null); - } - if (!$this->isSelectedDefaultStoreActive($postData, $groupModel)) { - throw new \Magento\Framework\Exception\LocalizedException( - __('An inactive store view cannot be saved as default store view') - ); - } - $groupModel->save(); - $this->_eventManager->dispatch('store_group_save', ['group' => $groupModel]); - $this->messageManager->addSuccess(__('You saved the store.')); + $postData = $this->processGroupSave($postData); break; - case 'store': - $eventName = 'store_edit'; - /** @var \Magento\Store\Model\Store $storeModel */ - $storeModel = $this->_objectManager->create(\Magento\Store\Model\Store::class); - $postData['store']['name'] = $this->filterManager->removeTags($postData['store']['name']); - if ($postData['store']['store_id']) { - $storeModel->load($postData['store']['store_id']); - } - $storeModel->setData($postData['store']); - if ($postData['store']['store_id'] == '') { - $storeModel->setId(null); - $eventName = 'store_add'; - } - $groupModel = $this->_objectManager->create( - \Magento\Store\Model\Group::class - )->load( - $storeModel->getGroupId() - ); - $storeModel->setWebsiteId($groupModel->getWebsiteId()); - if (!$storeModel->isActive() && $storeModel->isDefault()) { - throw new \Magento\Framework\Exception\LocalizedException( - __('The default store cannot be disabled') - ); - } - $storeModel->save(); - $this->_objectManager->get(\Magento\Store\Model\StoreManager::class)->reinitStores(); - $this->_eventManager->dispatch($eventName, ['store' => $storeModel]); - $this->messageManager->addSuccess(__('You saved the store view.')); + $postData = $this->processStoreSave($postData); break; default: $redirectResult->setPath('adminhtml/*/'); diff --git a/app/code/Magento/Backend/Cron/CleanCache.php b/app/code/Magento/Backend/Cron/CleanCache.php index 840e0dcfcfde0..7dc09da13d608 100644 --- a/app/code/Magento/Backend/Cron/CleanCache.php +++ b/app/code/Magento/Backend/Cron/CleanCache.php @@ -1,6 +1,6 @@ _path = $pathInMenuStructure . '/'; } $this->_logger = $logger; $this->setIteratorClass(\Magento\Backend\Model\Menu\Iterator::class); + $this->menuItemFactory = $menuItemFactory ?: ObjectManager::getInstance() + ->create(Factory::class); + $this->serializer = $serializer ?: ObjectManager::getInstance()->create(SerializerInterface::class); } /** * Add child to menu item * - * @param \Magento\Backend\Model\Menu\Item $item + * @param Item $item * @param string $parentId * @param int $index * @return void * @throws \InvalidArgumentException */ - public function add(\Magento\Backend\Model\Menu\Item $item, $parentId = null, $index = null) + public function add(Item $item, $parentId = null, $index = null) { if ($parentId !== null) { $parentItem = $this->get($parentId); @@ -69,13 +96,13 @@ public function add(\Magento\Backend\Model\Menu\Item $item, $parentId = null, $i * Retrieve menu item by id * * @param string $itemId - * @return \Magento\Backend\Model\Menu\Item|null + * @return Item|null */ public function get($itemId) { $result = null; + /** @var Item $item */ foreach ($this as $item) { - /** @var $item \Magento\Backend\Model\Menu\Item */ if ($item->getId() == $itemId) { $result = $item; break; @@ -116,8 +143,8 @@ public function move($itemId, $toItemId, $sortIndex = null) public function remove($itemId) { $result = false; + /** @var Item $item */ foreach ($this as $key => $item) { - /** @var $item \Magento\Backend\Model\Menu\Item */ if ($item->getId() == $itemId) { unset($this[$key]); $result = true; @@ -144,8 +171,8 @@ public function remove($itemId) public function reorder($itemId, $position) { $result = false; + /** @var Item $item */ foreach ($this as $key => $item) { - /** @var $item \Magento\Backend\Model\Menu\Item */ if ($item->getId() == $itemId) { unset($this[$key]); $this->add($item, null, $position); @@ -161,10 +188,10 @@ public function reorder($itemId, $position) /** * Check whether provided item is last in list * - * @param \Magento\Backend\Model\Menu\Item $item + * @param Item $item * @return bool */ - public function isLast(\Magento\Backend\Model\Menu\Item $item) + public function isLast(Item $item) { return $this->offsetGet(max(array_keys($this->getArrayCopy())))->getId() == $item->getId(); } @@ -172,12 +199,12 @@ public function isLast(\Magento\Backend\Model\Menu\Item $item) /** * Find first menu item that user is able to access * - * @return \Magento\Backend\Model\Menu\Item|null + * @return Item|null */ public function getFirstAvailable() { $result = null; - /** @var $item \Magento\Backend\Model\Menu\Item */ + /** @var Item $item */ foreach ($this as $item) { if ($item->isAllowed() && !$item->isDisabled()) { if ($item->hasChildren()) { @@ -198,7 +225,7 @@ public function getFirstAvailable() * Get parent items by item id * * @param string $itemId - * @return \Magento\Backend\Model\Menu\Item[] + * @return Item[] */ public function getParentItems($itemId) { @@ -217,8 +244,8 @@ public function getParentItems($itemId) */ protected function _findParentItems($menu, $itemId, &$parents) { + /** @var Item $item */ foreach ($menu as $item) { - /** @var $item \Magento\Backend\Model\Menu\Item */ if ($item->getId() == $itemId) { return true; } @@ -233,16 +260,54 @@ protected function _findParentItems($menu, $itemId, &$parents) } /** - * Hack to unset logger instance which cannot be serialized + * Serialize menu * * @return string */ public function serialize() { - $logger = $this->_logger; - unset($this->_logger); - $result = parent::serialize(); - $this->_logger = $logger; - return $result; + return $this->serializer->serialize($this->toArray()); + } + + /** + * Get menu data represented as an array + * + * @return array + */ + public function toArray() + { + $data = []; + foreach ($this as $item) { + $data[] = $item->toArray(); + } + return $data; + } + + /** + * Unserialize menu + * + * @param string $serialized + * @return void + */ + public function unserialize($serialized) + { + $data = $this->serializer->unserialize($serialized); + $this->populateFromArray($data); + } + + /** + * Populate the menu with data from array + * + * @param array $data + * @return void + */ + public function populateFromArray(array $data) + { + $items = []; + foreach ($data as $itemData) { + $item = $this->menuItemFactory->create($itemData); + $items[] = $item; + } + $this->exchangeArray($items); } } diff --git a/app/code/Magento/Backend/Model/Menu/AbstractDirector.php b/app/code/Magento/Backend/Model/Menu/AbstractDirector.php index 713b45fabd927..9d08ff6a186d8 100644 --- a/app/code/Magento/Backend/Model/Menu/AbstractDirector.php +++ b/app/code/Magento/Backend/Model/Menu/AbstractDirector.php @@ -1,6 +1,6 @@ query('/config/menu/*'); diff --git a/app/code/Magento/Backend/Model/Menu/Config/Menu/Dom.php b/app/code/Magento/Backend/Model/Menu/Config/Menu/Dom.php index 37da3a0aeaf3d..5d2c6dc2cbf36 100644 --- a/app/code/Magento/Backend/Model/Menu/Config/Menu/Dom.php +++ b/app/code/Magento/Backend/Model/Menu/Config/Menu/Dom.php @@ -1,6 +1,6 @@ _validator = $validator; $this->_validator->validate($data); - $this->_moduleManager = $moduleManager; $this->_acl = $authorization; $this->_scopeConfig = $scopeConfig; $this->_menuFactory = $menuFactory; $this->_urlModel = $urlModel; - $this->_moduleName = isset($data['module']) ? $data['module'] : 'Magento_Backend'; $this->_moduleList = $moduleList; - - $this->_id = $data['id']; - $this->_title = $data['title']; - $this->_action = $this->_getArgument($data, 'action'); - $this->_resource = $this->_getArgument($data, 'resource'); - $this->_dependsOnModule = $this->_getArgument($data, 'dependsOnModule'); - $this->_dependsOnConfig = $this->_getArgument($data, 'dependsOnConfig'); - $this->_tooltip = $this->_getArgument($data, 'toolTip', ''); + $this->populateFromArray($data); } /** @@ -208,6 +208,16 @@ public function getId() return $this->_id; } + /** + * Retrieve item target + * + * @return string|null + */ + public function getTarget() + { + return $this->target; + } + /** * Check whether item has subnodes * @@ -215,13 +225,13 @@ public function getId() */ public function hasChildren() { - return !is_null($this->_submenu) && (bool)$this->_submenu->count(); + return (null !== $this->_submenu) && (bool)$this->_submenu->count(); } /** * Retrieve submenu * - * @return \Magento\Backend\Model\Menu + * @return Menu */ public function getChildren() { @@ -425,7 +435,7 @@ protected function _isModuleDependenciesAvailable() protected function _isConfigDependenciesAvailable() { if ($this->_dependsOnConfig) { - return $this->_scopeConfig->isSetFlag((string)$this->_dependsOnConfig, \Magento\Store\Model\ScopeInterface::SCOPE_STORE); + return $this->_scopeConfig->isSetFlag((string)$this->_dependsOnConfig, ScopeInterface::SCOPE_STORE); } return true; } @@ -445,45 +455,55 @@ public function isAllowed() } /** - * @return string[] + * Get menu item data represented as an array + * + * @return array */ - public function __sleep() + public function toArray() { - if ($this->_submenu) { - $this->_serializedSubmenu = $this->_submenu->serialize(); - } return [ - '_parentId', - '_moduleName', - '_sortIndex', - '_dependsOnConfig', - '_id', - '_resource', - '_path', - '_action', - '_dependsOnModule', - '_tooltip', - '_title', - '_serializedSubmenu' + 'parent_id' => $this->_parentId, + 'module_name' => $this->_moduleName, + 'sort_index' => $this->_sortIndex, + 'depends_on_config' => $this->_dependsOnConfig, + 'id' => $this->_id, + 'resource' => $this->_resource, + 'path' => $this->_path, + 'action' => $this->_action, + 'depends_on_module' => $this->_dependsOnModule, + 'tooltip' => $this->_tooltip, + 'title' => $this->_title, + 'target' => $this->target, + 'sub_menu' => isset($this->_submenu) ? $this->_submenu->toArray() : null ]; } /** + * Populate the menu item with data from array + * + * @param array $data * @return void */ - public function __wakeup() + public function populateFromArray(array $data) { - $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); - $this->_moduleManager = $objectManager->get(\Magento\Framework\Module\Manager::class); - $this->_validator = $objectManager->get(\Magento\Backend\Model\Menu\Item\Validator::class); - $this->_acl = $objectManager->get(\Magento\Framework\AuthorizationInterface::class); - $this->_scopeConfig = $objectManager->get(\Magento\Framework\App\Config\ScopeConfigInterface::class); - $this->_menuFactory = $objectManager->get(\Magento\Backend\Model\MenuFactory::class); - $this->_urlModel = $objectManager->get(\Magento\Backend\Model\UrlInterface::class); - $this->_moduleList = $objectManager->get(\Magento\Framework\Module\ModuleListInterface::class); - if ($this->_serializedSubmenu) { - $this->_submenu = $this->_menuFactory->create(); - $this->_submenu->unserialize($this->_serializedSubmenu); + $this->_parentId = $this->_getArgument($data, 'parent_id'); + $this->_moduleName = $this->_getArgument($data, 'module_name', 'Magento_Backend'); + $this->_sortIndex = $this->_getArgument($data, 'sort_index'); + $this->_dependsOnConfig = $this->_getArgument($data, 'depends_on_config'); + $this->_id = $this->_getArgument($data, 'id'); + $this->_resource = $this->_getArgument($data, 'resource'); + $this->_path = $this->_getArgument($data, 'path', ''); + $this->_action = $this->_getArgument($data, 'action'); + $this->_dependsOnModule = $this->_getArgument($data, 'depends_on_module'); + $this->_tooltip = $this->_getArgument($data, 'tooltip', ''); + $this->_title = $this->_getArgument($data, 'title'); + $this->target = $this->_getArgument($data, 'target'); + if (isset($data['sub_menu'])) { + $menu = $this->_menuFactory->create(); + $menu->populateFromArray($data['sub_menu']); + $this->_submenu = $menu; + } else { + $this->_submenu = null; } } } diff --git a/app/code/Magento/Backend/Model/Menu/Item/Factory.php b/app/code/Magento/Backend/Model/Menu/Item/Factory.php index aabb6fb704d3f..8d2a7fdf37144 100644 --- a/app/code/Magento/Backend/Model/Menu/Item/Factory.php +++ b/app/code/Magento/Backend/Model/Menu/Item/Factory.php @@ -1,6 +1,6 @@ _encryptor = $encryptor; + $hostChecker = $hostChecker ?: ObjectManager::getInstance()->get(HostChecker::class); parent::__construct( $routeConfig, $request, @@ -133,7 +139,8 @@ public function __construct( $scopeConfig, $routeParamsPreprocessor, $scopeType, - $data + $data, + $hostChecker ); $this->_backendHelper = $backendHelper; $this->_menuConfig = $menuConfig; diff --git a/app/code/Magento/Backend/Model/Url/ScopeResolver.php b/app/code/Magento/Backend/Model/Url/ScopeResolver.php index 596465415d77f..923341d4a30c8 100644 --- a/app/code/Magento/Backend/Model/Url/ScopeResolver.php +++ b/app/code/Magento/Backend/Model/Url/ScopeResolver.php @@ -1,6 +1,6 @@ + * + * + * Condition\Implementation + * + * + * + * + * Registered condition can be used by ui component declaration in layout + * + * + * + * "condition" just another optional attribute of ui component declaration + */ +interface ConditionInterface +{ + /** + * Validate logical condition for ui component + * If validation passed block will be displayed + * + * @return bool + */ + public function validate(); +} diff --git a/app/code/Magento/Backend/Model/View/Layout/ConditionPool.php b/app/code/Magento/Backend/Model/View/Layout/ConditionPool.php new file mode 100644 index 0000000000000..ff73b8c519824 --- /dev/null +++ b/app/code/Magento/Backend/Model/View/Layout/ConditionPool.php @@ -0,0 +1,60 @@ +conditions = $conditions; + $this->objectManager = $objectManager; + } + + /** + * Returns condition by name + * If unknown condition requested throws InputException + * + * @param string $name + * @return ConditionInterface + * @throws InputException + */ + public function getCondition($name) + { + if (!isset($this->conditions[$name])) { + throw new InputException(__('Cannot apply unknown condition')); + } + return $this->objectManager->get($this->conditions[$name]); + } +} diff --git a/app/code/Magento/Backend/Model/View/Layout/Filter.php b/app/code/Magento/Backend/Model/View/Layout/Filter.php new file mode 100644 index 0000000000000..ed0752d2222fc --- /dev/null +++ b/app/code/Magento/Backend/Model/View/Layout/Filter.php @@ -0,0 +1,52 @@ +filters = $filters; + } + + /** + * Filter structure elements + * + * @param ScheduledStructure $scheduledStructure + * @param Structure $structure + * @return bool + */ + public function filterElement(ScheduledStructure $scheduledStructure, Structure $structure) + { + foreach ($this->filters as $filter) { + $filter->filterElement($scheduledStructure, $structure); + } + return true; + } +} diff --git a/app/code/Magento/Backend/Model/View/Layout/Filter/Acl.php b/app/code/Magento/Backend/Model/View/Layout/Filter/Acl.php index 7303bccc93893..ac2e86efeb62e 100644 --- a/app/code/Magento/Backend/Model/View/Layout/Filter/Acl.php +++ b/app/code/Magento/Backend/Model/View/Layout/Filter/Acl.php @@ -2,15 +2,30 @@ /** * ACL block filter * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Backend\Model\View\Layout\Filter; use Magento\Framework\View\Layout\ScheduledStructure; use Magento\Framework\View\Layout\Data\Structure; +use Magento\Backend\Model\View\Layout\FilterInterface; +use Magento\Backend\Model\View\Layout\StructureManager; +use Magento\Framework\App\ObjectManager; -class Acl +/** + * Class Acl + * + * Manage visibility of ui components and blocks at the backend according to ACL resources. + * If user role has corresponding resource block will be displayed. + * + * @see usage details in \Magento\Backend\Model\View\Layout\FilterInterface description + * + * Example of declaration in layout + * + * + */ +class Acl implements FilterInterface { /** * Authorization @@ -19,6 +34,11 @@ class Acl */ protected $authorization; + /** + * @var StructureManager + */ + private $structureManager; + /** * @param \Magento\Framework\AuthorizationInterface $authorization */ @@ -27,12 +47,25 @@ public function __construct(\Magento\Framework\AuthorizationInterface $authoriza $this->authorization = $authorization; } + /** + * @return StructureManager + */ + private function getStructureManager() + { + if (!$this->structureManager) { + $this->structureManager = ObjectManager::getInstance()->get(StructureManager::class); + } + return $this->structureManager; + } + /** * Delete elements that have "acl" attribute but value is "not allowed" * In any case, the "acl" attribute will be unset * * @param ScheduledStructure $scheduledStructure * @param Structure $structure + * + * @return void */ public function filterAclElements(ScheduledStructure $scheduledStructure, Structure $structure) { @@ -61,14 +94,18 @@ protected function removeElement( $elementName, $isChild = false ) { - $elementsToRemove = array_keys($structure->getChildren($elementName)); - $scheduledStructure->unsetElement($elementName); - foreach ($elementsToRemove as $element) { - $this->removeElement($scheduledStructure, $structure, $element, true); - } - if (!$isChild) { - $structure->unsetElement($elementName); - } + $this->getStructureManager()->removeElement($scheduledStructure, $structure, $elementName, $isChild); return $this; } + + /** + * @param ScheduledStructure $scheduledStructure + * @param Structure $structure + * @return bool + */ + public function filterElement(ScheduledStructure $scheduledStructure, Structure $structure) + { + $this->filterAclElements($scheduledStructure, $structure); + return true; + } } diff --git a/app/code/Magento/Backend/Model/View/Layout/Filter/Condition.php b/app/code/Magento/Backend/Model/View/Layout/Filter/Condition.php new file mode 100644 index 0000000000000..cbb72ccb51cc1 --- /dev/null +++ b/app/code/Magento/Backend/Model/View/Layout/Filter/Condition.php @@ -0,0 +1,67 @@ +structureManager = $structureManager; + $this->conditionPool = $conditionPool; + } + + /** + * Filter structure according to declared conditions + * + * @param ScheduledStructure $scheduledStructure + * @param Structure $structure + * @return bool + */ + public function filterElement(ScheduledStructure $scheduledStructure, Structure $structure) + { + foreach ($scheduledStructure->getElements() as $name => $data) { + list(, $data) = $data; + if (isset($data['attributes']['condition']) && $data['attributes']['condition']) { + $condition = $this->conditionPool->getCondition($data['attributes']['condition']); + if (!$condition->validate()) { + $this->structureManager->removeElement($scheduledStructure, $structure, $name); + } + } + } + return true; + } +} diff --git a/app/code/Magento/Backend/Model/View/Layout/FilterInterface.php b/app/code/Magento/Backend/Model/View/Layout/FilterInterface.php new file mode 100644 index 0000000000000..a1b0a302c0f66 --- /dev/null +++ b/app/code/Magento/Backend/Model/View/Layout/FilterInterface.php @@ -0,0 +1,38 @@ + + * + * + * Magento\Backend\Model\View\Layout\Filter\Acl + * + * + * + * + */ +interface FilterInterface +{ + /** + * Filter structure element + * + * @param ScheduledStructure $scheduledStructure + * @param Structure $structure + * @return bool + */ + public function filterElement(ScheduledStructure $scheduledStructure, Structure $structure); +} diff --git a/app/code/Magento/Backend/Model/View/Layout/GeneratorPool.php b/app/code/Magento/Backend/Model/View/Layout/GeneratorPool.php index 25b5c3cc0b6c8..a34d5929d5db7 100644 --- a/app/code/Magento/Backend/Model/View/Layout/GeneratorPool.php +++ b/app/code/Magento/Backend/Model/View/Layout/GeneratorPool.php @@ -1,12 +1,13 @@ filter) { + $this->filter = ObjectManager::getInstance()->get(FilterInterface::class); + } + return $this->filter; + } + /** * Build structure that is based on scheduled structure * @@ -54,7 +71,7 @@ public function __construct( protected function buildStructure(ScheduledStructure $scheduledStructure, Structure $structure) { parent::buildStructure($scheduledStructure, $structure); - $this->aclFilter->filterAclElements($scheduledStructure, $structure); + $this->getFilter()->filterElement($scheduledStructure, $structure); return $this; } } diff --git a/app/code/Magento/Backend/Model/View/Layout/Reader/Block.php b/app/code/Magento/Backend/Model/View/Layout/Reader/Block.php index a9ff03434775d..150a0c7a82191 100644 --- a/app/code/Magento/Backend/Model/View/Layout/Reader/Block.php +++ b/app/code/Magento/Backend/Model/View/Layout/Reader/Block.php @@ -1,6 +1,6 @@ getChildren($elementName)); + $scheduledStructure->unsetElement($elementName); + foreach ($elementsToRemove as $element) { + $this->removeElement($scheduledStructure, $structure, $element, true); + } + if (!$isChild) { + $structure->unsetElement($elementName); + } + return true; + } +} diff --git a/app/code/Magento/Backend/Model/View/Page/Builder.php b/app/code/Magento/Backend/Model/View/Page/Builder.php index 71d8f8241ee91..8b0fe73604137 100644 --- a/app/code/Magento/Backend/Model/View/Page/Builder.php +++ b/app/code/Magento/Backend/Model/View/Page/Builder.php @@ -1,6 +1,6 @@ sectionPool = $this->getMock( - \Magento\Framework\App\Config\ScopePool::class, - ['getScope', 'clean'], + $this->appConfig = $this->getMock( + \Magento\Framework\App\Config::class, + ['get'], [], '', false ); - $this->model = new \Magento\Backend\App\Config($this->sectionPool); + $this->model = new \Magento\Backend\App\Config($this->appConfig); } public function testGetValue() { $expectedValue = 'some value'; $path = 'some path'; - $configData = $this->getConfigDataMock('getValue'); - $configData->expects( - $this->once() - )->method( - 'getValue' - )->with( - $this->equalTo($path) - )->will( - $this->returnValue($expectedValue) - ); - $this->sectionPool->expects( + $this->appConfig->expects( $this->once() )->method( - 'getScope' + 'get' )->with( - $this->equalTo('default'), + $this->equalTo('system'), + $this->equalTo('default/' . $path), $this->isNull() )->will( - $this->returnValue($configData) + $this->returnValue($expectedValue) ); $this->assertEquals($expectedValue, $this->model->getValue($path)); } - public function testSetValue() - { - $value = 'some value'; - $path = 'some path'; - $configData = $this->getConfigDataMock('setValue'); - $configData->expects($this->once())->method('setValue')->with($this->equalTo($path), $this->equalTo($value)); - $this->sectionPool->expects( - $this->once() - )->method( - 'getScope' - )->with( - $this->equalTo('default'), - $this->isNull() - )->will( - $this->returnValue($configData) - ); - $this->model->setValue($path, $value); - } - /** + * @param string $configPath * @param mixed $configValue * @param bool $expectedResult * @dataProvider isSetFlagDataProvider */ - public function testIsSetFlag($configValue, $expectedResult) + public function testIsSetFlag($configPath, $configValue, $expectedResult) { - $path = 'some path'; - $configData = $this->getConfigDataMock('getValue'); - $configData->expects( - $this->once() + $this->appConfig->expects( + $this->any() )->method( - 'getValue' + 'get' )->with( - $this->equalTo($path) + $this->equalTo('system'), + $this->equalTo('default/' . $configPath) )->will( $this->returnValue($configValue) ); - $this->sectionPool->expects( - $this->once() - )->method( - 'getScope' - )->with( - $this->equalTo('default'), - $this->isNull() - )->will( - $this->returnValue($configData) - ); - $this->assertEquals($expectedResult, $this->model->isSetFlag($path)); + $this->assertEquals($expectedResult, $this->model->isSetFlag($configPath)); } public function isSetFlagDataProvider() { return [ - [0, false], - [true, true], - ['0', false], - ['', false], - ['some string', true], - [1, true] + ['a', 0, false], + ['b', true, true], + ['c', '0', false], + ['d', '', false], + ['e', 'some string', true], + ['f', 1, true] ]; } diff --git a/app/code/Magento/Backend/Test/Unit/App/Response/Http/FileFactoryTest.php b/app/code/Magento/Backend/Test/Unit/App/Response/Http/FileFactoryTest.php index 25c32fcaeec0b..8a4555ffa105a 100644 --- a/app/code/Magento/Backend/Test/Unit/App/Response/Http/FileFactoryTest.php +++ b/app/code/Magento/Backend/Test/Unit/App/Response/Http/FileFactoryTest.php @@ -1,6 +1,6 @@ activeMenuItemMock = $this->getMockBuilder(Item::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menuItemMock = $this->getMockBuilder(Item::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menuItemCheckerMock = $this->getMockBuilder(MenuItemChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $this->escaperMock = $this->getMockBuilder(Escaper::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->anchorRenderer = $this->objectManagerHelper->getObject( + AnchorRenderer::class, + [ + 'menuItemChecker' => $this->menuItemCheckerMock, + 'escaper' => $this->escaperMock + ] + ); + } + + public function testRenderAnchorLevelIsOne() + { + $title = 'Title'; + $html = 'Test html'; + $this->menuItemMock->expects($this->once())->method('getUrl')->willReturn('#'); + $this->menuItemMock->expects($this->once())->method('getTitle')->willReturn($title); + $this->escaperMock->expects($this->once())->method('escapeHtml')->with(__($title))->willReturn($html); + + $expected = '' + . '' . $html . '' + . ''; + + $this->assertEquals( + $expected, + $this->anchorRenderer->renderAnchor($this->activeMenuItemMock, $this->menuItemMock, 1) + ); + } + + /** + * @param bool $hasTarget + * @dataProvider targetDataProvider + */ + public function testRenderAnchorLevelIsNotOne($hasTarget) + { + $level = 0; + $title = 'Title'; + $html = 'Test html'; + $url = 'test/url'; + $tooltip = 'Anchor title'; + $onclick = ''; + $target = '_blank'; + $finalTarget = $hasTarget ? ('target=' . $target) : ''; + $this->menuItemMock->expects($this->any())->method('getTarget')->willReturn($hasTarget ? $target : null); + $this->menuItemMock->expects($this->once())->method('getUrl')->willReturn($url); + $this->menuItemMock->expects($this->once())->method('getTitle')->willReturn($title); + $this->escaperMock->expects($this->once())->method('escapeHtml')->with(__($title))->willReturn($html); + $this->menuItemMock->expects($this->once())->method('hasTooltip')->willReturn(true); + $this->menuItemMock->expects($this->any())->method('getTooltip')->willReturn(__($tooltip)); + $this->menuItemMock->expects($this->once())->method('hasClickCallback')->willReturn(true); + $this->menuItemMock->expects($this->once())->method('getClickCallback')->willReturn($onclick); + $this->menuItemCheckerMock->expects($this->once()) + ->method('isItemActive') + ->with($this->activeMenuItemMock, $this->menuItemMock, $level)->willReturn(true); + + $expected = '' . '' . $html + . '' . ''; + + $this->assertEquals( + $expected, + $this->anchorRenderer->renderAnchor($this->activeMenuItemMock, $this->menuItemMock, $level) + ); + } + + public function targetDataProvider() + { + return [ + 'item has target' => [true], + 'item does not have target' => [false] + ]; + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Block/Cache/AdditionalTest.php b/app/code/Magento/Backend/Test/Unit/Block/Cache/AdditionalTest.php index 7b78821bff498..395620cff9288 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Cache/AdditionalTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Cache/AdditionalTest.php @@ -1,6 +1,6 @@ menuItemMock = $this->getMockBuilder(Item::class) + ->disableOriginalConstructor() + ->getMock(); + $this->activeMenuItemMock = $this->getMockBuilder(Item::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menuItemChecker = new MenuItemChecker(); + } + + /** + * @param int $activeItemId + * @param int $itemId + * @param bool $isItem + * @param bool $expected + * @dataProvider dataProvider + */ + public function testIsItemActive($activeItemId, $itemId, $isItem, $expected) + { + $this->menuMock = $this->getMockBuilder(Menu::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menuItemMock->expects($this->any())->method('getId')->willReturn($itemId); + $this->activeMenuItemMock->expects($this->any())->method('getId')->willReturn($activeItemId); + $this->menuItemMock->expects($this->any())->method('getChildren')->willReturn($this->menuMock); + $this->menuMock->expects($this->any()) + ->method('get') + ->with($activeItemId) + ->willReturn($isItem ? $this->activeMenuItemMock : null); + $this->assertEquals( + $expected, + $this->menuItemChecker->isItemActive($this->activeMenuItemMock, $this->menuItemMock, 0) + ); + } + + public function testIsItemActiveLevelNotZero() + { + $this->assertFalse( + $this->menuItemChecker->isItemActive($this->activeMenuItemMock, $this->menuItemMock, 1) + ); + } + + public function dataProvider() + { + return [ + 'outputItemEquals' => ['1', '1', false, true], + 'outputItemIsChild' => ['1', '2', true, true], + 'outputItemIsChildNull' => ['1', '2', false, false], + ]; + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Block/MenuTest.php b/app/code/Magento/Backend/Test/Unit/Block/MenuTest.php new file mode 100644 index 0000000000000..ccc0e719aaecb --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Block/MenuTest.php @@ -0,0 +1,146 @@ +activeItemMock = $this->getMockBuilder(Item::class) + ->disableOriginalConstructor() + ->getMock(); + $this->urlMock = $this->getMockBuilder(UrlInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->iteratorFactoryMock = $this->getMockBuilder(IteratorFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->authSessionMock = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menuConfigMock = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->localeResolverMock = $this->getMockBuilder(ResolverInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menuItemChecker = $this->getMockBuilder(MenuItemChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $this->anchorRendererMock = $this->getMockBuilder(AnchorRenderer::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->menu = $this->objectManagerHelper->getObject( + Menu::class, + [ + 'url' => $this->urlMock, + 'iteratorFactory' => $this->iteratorFactoryMock, + 'authSession' => $this->authSessionMock, + 'menuConfig' => $this->menuConfigMock, + 'localeResolver' => $this->localeResolverMock, + 'menuItemChecker' => $this->menuItemCheckerMock, + 'anchorRenderer' => $this->anchorRendererMock + ] + ); + } + + public function testGetActiveItemModelMenuIsNotNull() + { + $this->menuModelMock = $this->getMockBuilder(MenuModel::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menu->setActive($this->activeItemMock); + $this->menuConfigMock->expects($this->once())->method('getMenu')->willReturn($this->menuModelMock); + $this->menuModelMock->expects($this->once()) + ->method('get') + ->willReturn($this->activeItemMock); + + $this->assertEquals($this->activeItemMock, $this->menu->getActiveItemModel()); + } + + public function testGetActiveItemModelMenuIsNull() + { + $this->menuModelMock = $this->getMockBuilder(MenuModel::class) + ->disableOriginalConstructor() + ->getMock(); + $this->menu->setActive(null); + $this->menuConfigMock->expects($this->once())->method('getMenu')->willReturn($this->menuModelMock); + $this->menuModelMock->expects($this->once()) + ->method('get') + ->willReturn(null); + + $this->assertFalse($this->menu->getActiveItemModel()); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php b/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php index 93ee165a541df..2eba4779d91e6 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Page/System/Config/Robots/ResetTest.php @@ -1,6 +1,6 @@ storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class); + $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $context = $objectHelper->getObject( + \Magento\Backend\Block\Template\Context::class, + [ + 'storeManager' => $this->storeManagerMock, + ] + ); + + $this->switcherBlock = $objectHelper->getObject( + \Magento\Backend\Block\Store\Switcher::class, + ['context' => $context] + ); + } + + public function testGetWebsites() + { + $websiteMock = $this->getMock(\Magento\Store\Model\Website::class, [], [], '', false); + $websites = [0 => $websiteMock, 1 => $websiteMock]; + $this->storeManagerMock->expects($this->once())->method('getWebsites')->will($this->returnValue($websites)); + $this->assertEquals($websites, $this->switcherBlock->getWebsites()); + } + + public function testGetWebsitesIfSetWebsiteIds() + { + $websiteMock = $this->getMock(\Magento\Store\Model\Website::class, [], [], '', false); + $websites = [0 => $websiteMock, 1 => $websiteMock]; + $this->storeManagerMock->expects($this->once())->method('getWebsites')->will($this->returnValue($websites)); + + $this->switcherBlock->setWebsiteIds([1]); + $expected = [1 => $websiteMock]; + $this->assertEquals($expected, $this->switcherBlock->getWebsites()); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Button/SplitTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Button/SplitTest.php index 648af09935dfd..ada8575ae8d9f 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Button/SplitTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Button/SplitTest.php @@ -1,6 +1,6 @@ _gridMock = $this->getMock( - \Magento\Backend\Block\Widget\Grid::class, - ['getId', 'getCollection'], - [], - '', - false - ); - $this->_gridMock->expects($this->any())->method('getId')->will($this->returnValue('test_grid')); - - $this->_layoutMock = $this->getMock( - \Magento\Framework\View\Layout::class, - ['getParentName', 'getBlock', 'helper'], - [], - '', - false, - false - ); + $this->_gridMock = $this->getMockBuilder(\Magento\Backend\Block\Widget\Grid::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->setMethods(['getId', 'getCollection']) + ->getMock(); + $this->_gridMock->expects($this->any()) + ->method('getId') + ->willReturn('test_grid'); - $this->_layoutMock->expects( - $this->any() - )->method( - 'getParentName' - )->with( - 'test_grid_massaction' - )->will( - $this->returnValue('test_grid') - ); - $this->_layoutMock->expects( - $this->any() - )->method( - 'getBlock' - )->with( - 'test_grid' - )->will( - $this->returnValue($this->_gridMock) - ); + $this->_layoutMock = $this->getMockBuilder(\Magento\Framework\View\Layout::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->setMethods(['getParentName', 'getBlock', 'helper']) + ->getMock(); + $this->_layoutMock->expects($this->any()) + ->method('getParentName') + ->with('test_grid_massaction') + ->willReturn('test_grid'); + $this->_layoutMock->expects($this->any()) + ->method('getBlock') + ->with('test_grid') + ->willReturn($this->_gridMock); + + $this->_requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); - $this->_requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false); + $this->_urlModelMock = $this->getMockBuilder(\Magento\Backend\Model\Url::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); - $this->_urlModelMock = $this->getMock(\Magento\Backend\Model\Url::class, [], [], '', false); + $this->visibilityCheckerMock = $this->getMockBuilder(VisibilityChecker::class) + ->getMockForAbstractClass(); $arguments = [ 'layout' => $this->_layoutMock, 'request' => $this->_requestMock, 'urlBuilder' => $this->_urlModelMock, - 'data' => ['massaction_id_field' => 'test_id', 'massaction_id_filter' => 'test_id'], + 'data' => ['massaction_id_field' => 'test_id', 'massaction_id_filter' => 'test_id'] ]; $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -124,26 +126,24 @@ public function testMassactionDefaultValues() } /** - * @param $itemId - * @param $item + * @param string $itemId + * @param \Magento\Framework\DataObject $item * @param $expectedItem \Magento\Framework\DataObject - * @dataProvider itemsDataProvider + * @dataProvider itemsProcessingDataProvider */ public function testItemsProcessing($itemId, $item, $expectedItem) { - $this->_urlModelMock->expects( - $this->any() - )->method( - 'getBaseUrl' - )->will( - $this->returnValue('http://localhost/index.php') - ); + $this->_urlModelMock->expects($this->any()) + ->method('getBaseUrl') + ->willReturn('http://localhost/index.php'); $urlReturnValueMap = [ ['*/*/test1', [], 'http://localhost/index.php/backend/admin/test/test1'], ['*/*/test2', [], 'http://localhost/index.php/backend/admin/test/test2'], ]; - $this->_urlModelMock->expects($this->any())->method('getUrl')->will($this->returnValueMap($urlReturnValueMap)); + $this->_urlModelMock->expects($this->any()) + ->method('getUrl') + ->willReturnMap($urlReturnValueMap); $this->_block->addItem($itemId, $item); $this->assertEquals(1, $this->_block->getCount()); @@ -157,7 +157,10 @@ public function testItemsProcessing($itemId, $item, $expectedItem) $this->assertNull($this->_block->getItem($itemId)); } - public function itemsDataProvider() + /** + * @return array + */ + public function itemsProcessingDataProvider() { return [ [ @@ -186,22 +189,17 @@ public function itemsDataProvider() } /** - * @param $param - * @param $expectedJson - * @param $expected + * @param string $param + * @param string $expectedJson + * @param array $expected * @dataProvider selectedDataProvider */ public function testSelected($param, $expectedJson, $expected) { - $this->_requestMock->expects( - $this->any() - )->method( - 'getParam' - )->with( - $this->_block->getFormFieldNameInternal() - )->will( - $this->returnValue($param) - ); + $this->_requestMock->expects($this->any()) + ->method('getParam') + ->with($this->_block->getFormFieldNameInternal()) + ->willReturn($param); $this->assertEquals($expectedJson, $this->_block->getSelectedJson()); $this->assertEquals($expected, $this->_block->getSelected()); @@ -262,6 +260,9 @@ public function testGetGridIdsJsonWithUseSelectAll(array $items, $result) $this->assertEquals($result, $this->_block->getGridIdsJson()); } + /** + * @return array + */ public function dataProviderGetGridIdsJsonWithUseSelectAll() { return [ @@ -279,4 +280,71 @@ public function dataProviderGetGridIdsJsonWithUseSelectAll() ], ]; } + + /** + * @param string $itemId + * @param array|\Magento\Framework\DataObject $item + * @param int $count + * @param bool $withVisibilityChecker + * @param bool $isVisible + * @dataProvider addItemDataProvider + */ + public function testAddItem($itemId, $item, $count, $withVisibilityChecker, $isVisible) + { + $this->visibilityCheckerMock->expects($this->any()) + ->method('isVisible') + ->willReturn($isVisible); + + if ($withVisibilityChecker) { + $item['visible'] = $this->visibilityCheckerMock; + } + + $urlReturnValueMap = [ + ['*/*/test1', [], 'http://localhost/index.php/backend/admin/test/test1'], + ['*/*/test2', [], 'http://localhost/index.php/backend/admin/test/test2'], + ]; + $this->_urlModelMock->expects($this->any()) + ->method('getUrl') + ->willReturnMap($urlReturnValueMap); + + $this->_block->addItem($itemId, $item); + $this->assertEquals($count, $this->_block->getCount()); + } + + /** + * @return array + */ + public function addItemDataProvider() + { + return [ + [ + 'itemId' => 'test1', + 'item' => ['label' => 'Test 1', 'url' => '*/*/test1'], + 'count' => 1, + 'withVisibilityChecker' => false, + '$isVisible' => false, + ], + [ + 'itemId' => 'test2', + 'item' => ['label' => 'Test 2', 'url' => '*/*/test2'], + 'count' => 1, + 'withVisibilityChecker' => false, + 'isVisible' => true, + ], + [ + 'itemId' => 'test1', + 'item' => ['label' => 'Test 1. Hide', 'url' => '*/*/test1'], + 'count' => 0, + 'withVisibilityChecker' => true, + 'isVisible' => false, + ], + [ + 'itemId' => 'test2', + 'item' => ['label' => 'Test 2. Does not hide', 'url' => '*/*/test2'], + 'count' => 1, + 'withVisibilityChecker' => true, + 'isVisible' => true, + ] + ]; + } } diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/SerializerTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/SerializerTest.php index 1d7caa432e59e..627b6dbec4350 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/SerializerTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/SerializerTest.php @@ -1,6 +1,6 @@ stateMock = $this->getMockBuilder(State::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(MessageManager::class) + ->getMockForAbstractClass(); + + $this->requestMock = $this->getMockBuilder(Request::class) + ->getMockForAbstractClass(); + + $this->cacheTypeListMock = $this->getMockBuilder(CacheTypeList::class) + ->getMockForAbstractClass(); + + $this->cacheStateMock = $this->getMockBuilder(CacheState::class) + ->getMockForAbstractClass(); + + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $this->redirectMock->expects($this->once()) + ->method('setPath') + ->with('adminhtml/*') + ->willReturnSelf(); + $resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + + $contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $contextMock->expects($this->once()) + ->method('getMessageManager') + ->willReturn($this->messageManagerMock); + $contextMock->expects($this->once()) + ->method('getResultFactory') + ->willReturn($resultFactoryMock); + $contextMock->expects($this->once()) + ->method('getRequest') + ->willReturn($this->requestMock); + + $this->controller = $objectManagerHelper->getObject( + MassDisable::class, + [ + 'context' => $contextMock, + 'cacheTypeList' => $this->cacheTypeListMock, + 'cacheState' => $this->cacheStateMock + ] + ); + $objectManagerHelper->setBackwardCompatibleProperty($this->controller, 'state', $this->stateMock); + } + + public function testExecuteInProductionMode() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_PRODUCTION); + + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with('You can\'t change status of cache type(s) in production mode', null) + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteInvalidTypeCache() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn(['someCache']); + + $this->messageManagerMock->expects($this->once()) + ->method('addError') + ->with('Specified cache type(s) don\'t exist: someCache') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteWithException() + { + $exception = new \Exception(); + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->willThrowException($exception); + + $this->messageManagerMock->expects($this->once()) + ->method('addException') + ->with($exception, 'An error occurred while disabling cache.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteSuccess() + { + $cacheType = 'pageCache'; + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn([$cacheType]); + + $this->cacheStateMock->expects($this->once()) + ->method('isEnabled') + ->with($cacheType) + ->willReturn(true); + $this->cacheStateMock->expects($this->once()) + ->method('setEnabled') + ->with($cacheType, false); + $this->cacheStateMock->expects($this->once()) + ->method('persist'); + + $this->messageManagerMock->expects($this->once()) + ->method('addSuccess') + ->with('1 cache type(s) disabled.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php new file mode 100644 index 0000000000000..aff391e033209 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Cache/MassEnableTest.php @@ -0,0 +1,224 @@ +stateMock = $this->getMockBuilder(State::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(MessageManager::class) + ->getMockForAbstractClass(); + + $this->requestMock = $this->getMockBuilder(Request::class) + ->getMockForAbstractClass(); + + $this->cacheTypeListMock = $this->getMockBuilder(CacheTypeList::class) + ->getMockForAbstractClass(); + + $this->cacheStateMock = $this->getMockBuilder(CacheState::class) + ->getMockForAbstractClass(); + + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $this->redirectMock->expects($this->once()) + ->method('setPath') + ->with('adminhtml/*') + ->willReturnSelf(); + $resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + + $contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $contextMock->expects($this->once()) + ->method('getMessageManager') + ->willReturn($this->messageManagerMock); + $contextMock->expects($this->once()) + ->method('getResultFactory') + ->willReturn($resultFactoryMock); + $contextMock->expects($this->once()) + ->method('getRequest') + ->willReturn($this->requestMock); + + $this->controller = $objectManagerHelper->getObject( + MassEnable::class, + [ + 'context' => $contextMock, + 'cacheTypeList' => $this->cacheTypeListMock, + 'cacheState' => $this->cacheStateMock + ] + ); + $objectManagerHelper->setBackwardCompatibleProperty($this->controller, 'state', $this->stateMock); + } + + public function testExecuteInProductionMode() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_PRODUCTION); + + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with('You can\'t change status of cache type(s) in production mode', null) + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteInvalidTypeCache() + { + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn(['someCache']); + + $this->messageManagerMock->expects($this->once()) + ->method('addError') + ->with('Specified cache type(s) don\'t exist: someCache') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteWithException() + { + $exception = new \Exception(); + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->willThrowException($exception); + + $this->messageManagerMock->expects($this->once()) + ->method('addException') + ->with($exception, 'An error occurred while enabling cache.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } + + public function testExecuteSuccess() + { + $cacheType = 'pageCache'; + + $this->stateMock->expects($this->once()) + ->method('getMode') + ->willReturn(State::MODE_DEVELOPER); + + $this->cacheTypeListMock->expects($this->once()) + ->method('getTypes') + ->willReturn([ + 'pageCache' => [ + 'id' => 'pageCache', + 'label' => 'Cache of Page' + ] + ]); + + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('types') + ->willReturn([$cacheType]); + + $this->cacheStateMock->expects($this->once()) + ->method('isEnabled') + ->with($cacheType) + ->willReturn(false); + $this->cacheStateMock->expects($this->once()) + ->method('setEnabled') + ->with($cacheType, true); + $this->cacheStateMock->expects($this->once()) + ->method('persist'); + + $this->messageManagerMock->expects($this->once()) + ->method('addSuccess') + ->with('1 cache type(s) enabled.') + ->willReturnSelf(); + + $this->assertSame($this->redirectMock, $this->controller->execute()); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/AbstractTestCase.php b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/AbstractTestCase.php index 43143f0587ee7..16e109b516410 100644 --- a/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/AbstractTestCase.php +++ b/app/code/Magento/Backend/Test/Unit/Controller/Adminhtml/Dashboard/AbstractTestCase.php @@ -1,6 +1,6 @@ resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->pageMock = $this->getMockBuilder(Page::class) + ->disableOriginalConstructor() + ->getMock(); + $this->pageConfigMock = $this->getMockBuilder(Config::class) + ->setMethods(['getTitle']) + ->disableOriginalConstructor() + ->getMock(); + $this->titleMock = $this->getMockBuilder(Title::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->indexController = $this->objectManagerHelper->getObject( + Index::class, + [ + 'resultFactory' => $this->resultFactoryMock + ] + ); + } + + public function testIndex() + { + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_PAGE) + ->willReturn($this->pageMock); + $this->pageMock->expects($this->once()) + ->method('setActiveMenu') + ->with('Magento_Backend::system_store') + ->willReturnSelf(); + $this->pageMock->expects($this->exactly(2)) + ->method('addBreadcrumb') + ->withConsecutive( + [__('Stores'), __('Stores')], + [__('All Stores'), __('All Stores')] + ); + $this->pageMock->expects($this->once()) + ->method('getConfig') + ->willReturn($this->pageConfigMock); + $this->pageConfigMock->expects($this->once())->method('getTitle')->willReturn($this->titleMock); + $this->titleMock->expects($this->once())->method('prepend')->with(__('Stores'))->willReturn($this->pageMock); + + $this->assertSame($this->pageMock, $this->indexController->execute()); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Cron/CleanCacheTest.php b/app/code/Magento/Backend/Test/Unit/Cron/CleanCacheTest.php index 4386e7c395300..7e8fbfe197bf9 100644 --- a/app/code/Magento/Backend/Test/Unit/Cron/CleanCacheTest.php +++ b/app/code/Magento/Backend/Test/Unit/Cron/CleanCacheTest.php @@ -1,6 +1,6 @@ _factoryMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Factory::class, [], [], '', false); - $this->_menuMock = $this->getMock( - \Magento\Backend\Model\Menu::class, - [], - [$this->getMock(\Psr\Log\LoggerInterface::class)] + $this->factoryMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Factory::class, [], [], '', false); + $this->menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false); + + $this->model = (new ObjectManager($this))->getObject( + \Magento\Backend\Model\Menu\Builder::class, + [ + 'menuItemFactory' => $this->factoryMock + ] ); - - $this->_model = new \Magento\Backend\Model\Menu\Builder($this->_factoryMock, $this->_menuMock); } public function testProcessCommand() @@ -41,20 +44,20 @@ public function testProcessCommand() $command2 = $this->getMock(\Magento\Backend\Model\Menu\Builder\Command\Update::class, [], [], '', false); $command2->expects($this->any())->method('getId')->will($this->returnValue(1)); $command->expects($this->once())->method('chain')->with($this->equalTo($command2)); - $this->_model->processCommand($command); - $this->_model->processCommand($command2); + $this->model->processCommand($command); + $this->model->processCommand($command2); } public function testGetResultBuildsTreeStructure() { $item1 = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); - $item1->expects($this->once())->method('getChildren')->will($this->returnValue($this->_menuMock)); - $this->_factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1)); + $item1->expects($this->once())->method('getChildren')->will($this->returnValue($this->menuMock)); + $this->factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1)); $item2 = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); - $this->_factoryMock->expects($this->at(1))->method('create')->will($this->returnValue($item2)); + $this->factoryMock->expects($this->at(1))->method('create')->will($this->returnValue($item2)); - $this->_menuMock->expects( + $this->menuMock->expects( $this->at(0) )->method( 'add' @@ -64,7 +67,7 @@ public function testGetResultBuildsTreeStructure() $this->equalTo(2) ); - $this->_menuMock->expects( + $this->menuMock->expects( $this->at(1) )->method( 'add' @@ -74,7 +77,7 @@ public function testGetResultBuildsTreeStructure() $this->equalTo(4) ); - $this->_model->processCommand( + $this->model->processCommand( new \Magento\Backend\Model\Menu\Builder\Command\Add( [ 'id' => 'item1', @@ -85,7 +88,7 @@ public function testGetResultBuildsTreeStructure() ] ) ); - $this->_model->processCommand( + $this->model->processCommand( new \Magento\Backend\Model\Menu\Builder\Command\Add( [ 'id' => 'item2', @@ -98,12 +101,12 @@ public function testGetResultBuildsTreeStructure() ) ); - $this->_model->getResult($this->_menuMock); + $this->model->getResult($this->menuMock); } public function testGetResultSkipsRemovedItems() { - $this->_model->processCommand( + $this->model->processCommand( new \Magento\Backend\Model\Menu\Builder\Command\Add( [ 'id' => 1, @@ -113,11 +116,11 @@ public function testGetResultSkipsRemovedItems() ] ) ); - $this->_model->processCommand(new \Magento\Backend\Model\Menu\Builder\Command\Remove(['id' => 1])); + $this->model->processCommand(new \Magento\Backend\Model\Menu\Builder\Command\Remove(['id' => 1])); - $this->_menuMock->expects($this->never())->method('addChild'); + $this->menuMock->expects($this->never())->method('addChild'); - $this->_model->getResult($this->_menuMock); + $this->model->getResult($this->menuMock); } /** @@ -126,9 +129,9 @@ public function testGetResultSkipsRemovedItems() public function testGetResultSkipItemsWithInvalidParent() { $item1 = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); - $this->_factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1)); + $this->factoryMock->expects($this->any())->method('create')->will($this->returnValue($item1)); - $this->_model->processCommand( + $this->model->processCommand( new \Magento\Backend\Model\Menu\Builder\Command\Add( [ 'id' => 'item1', @@ -140,6 +143,6 @@ public function testGetResultSkipItemsWithInvalidParent() ) ); - $this->_model->getResult($this->_menuMock); + $this->model->getResult($this->menuMock); } } diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/ConverterTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/ConverterTest.php index a05526c715815..e60f32218138b 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/ConverterTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/ConverterTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/_files/valid_menu.xml b/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/_files/valid_menu.xml index 4627fb49a031f..d60f5a0cd37da 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/_files/valid_menu.xml +++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/Config/_files/valid_menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php index dee7518be3ac9..424cf696601ba 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/ConfigTest.php @@ -1,63 +1,47 @@ _cacheInstanceMock = $this->getMock( + $this->cacheInstanceMock = $this->getMock( \Magento\Framework\App\Cache\Type\Config::class, [], [], @@ -65,15 +49,7 @@ protected function setUp() false ); - $this->_directorMock = $this->getMock( - \Magento\Backend\Model\Menu\AbstractDirector::class, - [], - [], - '', - false - ); - - $this->_menuFactoryMock = $this->getMock( + $menuFactoryMock = $this->getMock( \Magento\Backend\Model\MenuFactory::class, ['create'], [], @@ -81,7 +57,7 @@ protected function setUp() false ); - $this->_configReaderMock = $this->getMock( + $this->configReaderMock = $this->getMock( \Magento\Backend\Model\Menu\Config\Reader::class, [], [], @@ -89,30 +65,15 @@ protected function setUp() false ); - $this->_eventManagerMock = $this->getMock( - \Magento\Framework\Event\ManagerInterface::class, - [], - [], - '', - false, - false - ); - - $this->_logger = $this->getMock(\Psr\Log\LoggerInterface::class); - - $this->_menuMock = $this->getMock( - \Magento\Backend\Model\Menu::class, - [], - [$this->getMock(\Psr\Log\LoggerInterface::class)] - ); + $this->logger = $this->getMock(\Psr\Log\LoggerInterface::class); - $this->_menuBuilderMock = $this->getMock(\Magento\Backend\Model\Menu\Builder::class, [], [], '', false); + $this->menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false); - $this->_menuFactoryMock->expects($this->any())->method('create')->will($this->returnValue($this->_menuMock)); + $this->menuBuilderMock = $this->getMock(\Magento\Backend\Model\Menu\Builder::class, [], [], '', false); - $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); + $menuFactoryMock->expects($this->any())->method('create')->will($this->returnValue($this->menuMock)); - $this->_configReaderMock->expects($this->any())->method('read')->will($this->returnValue([])); + $this->configReaderMock->expects($this->any())->method('read')->will($this->returnValue([])); $appState = $this->getMock(\Magento\Framework\App\State::class, ['getAreaCode'], [], '', false); $appState->expects( @@ -123,22 +84,22 @@ protected function setUp() $this->returnValue(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE) ); - $this->_model = new \Magento\Backend\Model\Menu\Config( - $this->_menuBuilderMock, - $this->_directorMock, - $this->_menuFactoryMock, - $this->_configReaderMock, - $this->_cacheInstanceMock, - $this->_eventManagerMock, - $this->_logger, - $scopeConfig, - $appState + $this->model = (new ObjectManager($this))->getObject( + \Magento\Backend\Model\Menu\Config::class, + [ + 'menuBuilder' => $this->menuBuilderMock, + 'menuFactory' => $menuFactoryMock, + 'configReader' => $this->configReaderMock, + 'configCacheType' => $this->cacheInstanceMock, + 'logger' => $this->logger, + 'appState' => $appState, + ] ); } public function testGetMenuWithCachedObjectReturnsUnserializedObject() { - $this->_cacheInstanceMock->expects( + $this->cacheInstanceMock->expects( $this->once() )->method( 'load' @@ -148,14 +109,14 @@ public function testGetMenuWithCachedObjectReturnsUnserializedObject() $this->returnValue('menu_cache') ); - $this->_menuMock->expects($this->once())->method('unserialize')->with('menu_cache'); + $this->menuMock->expects($this->once())->method('unserialize')->with('menu_cache'); - $this->assertEquals($this->_menuMock, $this->_model->getMenu()); + $this->assertEquals($this->menuMock, $this->model->getMenu()); } public function testGetMenuWithNotCachedObjectBuidlsObject() { - $this->_cacheInstanceMock->expects( + $this->cacheInstanceMock->expects( $this->at(0) )->method( 'load' @@ -165,17 +126,17 @@ public function testGetMenuWithNotCachedObjectBuidlsObject() $this->returnValue(false) ); - $this->_configReaderMock->expects($this->once())->method('read')->will($this->returnValue([])); + $this->configReaderMock->expects($this->once())->method('read')->will($this->returnValue([])); - $this->_menuBuilderMock->expects( + $this->menuBuilderMock->expects( $this->exactly(1) )->method( 'getResult' )->will( - $this->returnValue($this->_menuMock) + $this->returnValue($this->menuMock) ); - $this->assertEquals($this->_menuMock, $this->_model->getMenu()); + $this->assertEquals($this->menuMock, $this->model->getMenu()); } /** @@ -186,7 +147,7 @@ public function testGetMenuWithNotCachedObjectBuidlsObject() public function testGetMenuExceptionLogged($expectedException) { $this->setExpectedException($expectedException); - $this->_menuBuilderMock->expects( + $this->menuBuilderMock->expects( $this->exactly(1) )->method( 'getResult' @@ -194,7 +155,7 @@ public function testGetMenuExceptionLogged($expectedException) $this->throwException(new $expectedException()) ); - $this->_model->getMenu(); + $this->model->getMenu(); } public function getMenuExceptionLoggedDataProvider() @@ -208,9 +169,9 @@ public function getMenuExceptionLoggedDataProvider() public function testGetMenuGenericExceptionIsNotLogged() { - $this->_logger->expects($this->never())->method('critical'); + $this->logger->expects($this->never())->method('critical'); - $this->_menuBuilderMock->expects( + $this->menuBuilderMock->expects( $this->exactly(1) )->method( 'getResult' @@ -218,7 +179,7 @@ public function testGetMenuGenericExceptionIsNotLogged() $this->throwException(new \Exception()) ); try { - $this->_model->getMenu(); + $this->model->getMenu(); } catch (\Exception $e) { return; } diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/Director/DirectorTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/Director/DirectorTest.php index 550a0a4354832..f4b40aa20fb30 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/Menu/Director/DirectorTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/Director/DirectorTest.php @@ -1,6 +1,6 @@ _items['item1'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); - $this->_items['item1']->expects($this->any())->method('getId')->will($this->returnValue('item1')); - $this->_items['item1']->expects($this->any())->method('isDisabled')->will($this->returnValue(false)); - $this->_items['item1']->expects($this->any())->method('isAllowed')->will($this->returnValue(true)); - - $this->_items['item2'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); - $this->_items['item2']->expects($this->any())->method('getId')->will($this->returnValue('item2')); - $this->_items['item2']->expects($this->any())->method('isDisabled')->will($this->returnValue(true)); - $this->_items['item2']->expects($this->any())->method('isAllowed')->will($this->returnValue(true)); - - $this->_items['item3'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); - $this->_items['item3']->expects($this->any())->method('getId')->will($this->returnValue('item3')); - $this->_items['item3']->expects($this->any())->method('isDisabled')->will($this->returnValue(false)); - $this->_items['item3']->expects($this->any())->method('isAllowed')->will($this->returnValue(false)); - - $loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class); - - $this->_menuModel = new \Magento\Backend\Model\Menu($loggerMock); + $this->items['item1'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); + $this->items['item1']->expects($this->any())->method('getId')->will($this->returnValue('item1')); + $this->items['item1']->expects($this->any())->method('isDisabled')->will($this->returnValue(false)); + $this->items['item1']->expects($this->any())->method('isAllowed')->will($this->returnValue(true)); + + $this->items['item2'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); + $this->items['item2']->expects($this->any())->method('getId')->will($this->returnValue('item2')); + $this->items['item2']->expects($this->any())->method('isDisabled')->will($this->returnValue(true)); + $this->items['item2']->expects($this->any())->method('isAllowed')->will($this->returnValue(true)); + + $this->items['item3'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); + $this->items['item3']->expects($this->any())->method('getId')->will($this->returnValue('item3')); + $this->items['item3']->expects($this->any())->method('isDisabled')->will($this->returnValue(false)); + $this->items['item3']->expects($this->any())->method('isAllowed')->will($this->returnValue(false)); + + $this->menuModel = (new ObjectManager($this))->getObject(\Magento\Backend\Model\Menu::class); } public function testLoopWithAllItemsDisabledDoesntIterate() { - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator( - $this->_menuModel->getIterator() + $this->menuModel->getIterator() ); $items = []; @@ -59,15 +59,15 @@ public function testLoopWithAllItemsDisabledDoesntIterate() public function testLoopIteratesOnlyValidItems() { - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->_items['item1']); + $this->menuModel->add($this->items['item1']); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator( - $this->_menuModel->getIterator() + $this->menuModel->getIterator() ); $items = []; @@ -79,16 +79,16 @@ public function testLoopIteratesOnlyValidItems() public function testLoopIteratesDosntIterateDisabledItems() { - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->_items['item1']); - $this->_menuModel->add($this->_items['item2']); + $this->menuModel->add($this->items['item1']); + $this->menuModel->add($this->items['item2']); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator( - $this->_menuModel->getIterator() + $this->menuModel->getIterator() ); $items = []; @@ -100,16 +100,16 @@ public function testLoopIteratesDosntIterateDisabledItems() public function testLoopIteratesDosntIterateNotAllowedItems() { - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->_items['item1']); - $this->_menuModel->add($this->_items['item3']); + $this->menuModel->add($this->items['item1']); + $this->menuModel->add($this->items['item3']); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator( - $this->_menuModel->getIterator() + $this->menuModel->getIterator() ); $items = []; @@ -121,17 +121,17 @@ public function testLoopIteratesDosntIterateNotAllowedItems() public function testLoopIteratesMixedItems() { - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->_items['item1']); - $this->_menuModel->add($this->_items['item2']); - $this->_menuModel->add($this->_items['item3']); + $this->menuModel->add($this->items['item1']); + $this->menuModel->add($this->items['item2']); + $this->menuModel->add($this->items['item3']); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); - $this->_menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); + $this->menuModel->add($this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false)); $filterIteratorModel = new \Magento\Backend\Model\Menu\Filter\Iterator( - $this->_menuModel->getIterator() + $this->menuModel->getIterator() ); $items = []; diff --git a/app/code/Magento/Backend/Test/Unit/Model/Menu/Item/ValidatorTest.php b/app/code/Magento/Backend/Test/Unit/Model/Menu/Item/ValidatorTest.php index 5d7e050d32468..0391c91fa6c0e 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/Menu/Item/ValidatorTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/Menu/Item/ValidatorTest.php @@ -1,6 +1,6 @@ 'Item Title', 'action' => '/system/config', 'resource' => 'Magento_Config::config', - 'dependsOnModule' => 'Magento_Backend', - 'dependsOnConfig' => 'system/config/isEnabled', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', 'tooltip' => 'Item tooltip', ]; @@ -76,15 +74,15 @@ protected function setUp() ); $this->_urlModelMock = $this->getMock(\Magento\Backend\Model\Url::class, [], [], '', false); $this->_moduleManager = $this->getMock(\Magento\Framework\Module\Manager::class, [], [], '', false); - $this->_validatorMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Validator::class); - $this->_validatorMock->expects($this->any())->method('validate'); + $validatorMock = $this->getMock(\Magento\Backend\Model\Menu\Item\Validator::class); + $validatorMock->expects($this->any())->method('validate'); $this->_moduleListMock = $this->getMock(\Magento\Framework\Module\ModuleListInterface::class); - $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->_model = $helper->getObject( + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->_model = $this->objectManager->getObject( \Magento\Backend\Model\Menu\Item::class, [ - 'validator' => $this->_validatorMock, + 'validator' => $validatorMock, 'authorization' => $this->_aclMock, 'scopeConfig' => $this->_scopeConfigMock, 'menuFactory' => $this->_menuFactoryMock, @@ -99,8 +97,7 @@ protected function setUp() public function testGetUrlWithEmptyActionReturnsHashSign() { $this->_params['action'] = ''; - $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $item = $helper->getObject( + $item = $this->objectManager->getObject( \Magento\Backend\Model\Menu\Item::class, ['menuFactory' => $this->_menuFactoryMock, 'data' => $this->_params] ); @@ -129,8 +126,7 @@ public function testHasClickCallbackReturnsFalseIfItemHasAction() public function testHasClickCallbackReturnsTrueIfItemHasNoAction() { $this->_params['action'] = ''; - $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $item = $helper->getObject( + $item = $this->objectManager->getObject( \Magento\Backend\Model\Menu\Item::class, ['menuFactory' => $this->_menuFactoryMock, 'data' => $this->_params] ); @@ -140,8 +136,7 @@ public function testHasClickCallbackReturnsTrueIfItemHasNoAction() public function testGetClickCallbackReturnsStoppingJsIfItemDoesntHaveAction() { $this->_params['action'] = ''; - $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $item = $helper->getObject( + $item = $this->objectManager->getObject( \Magento\Backend\Model\Menu\Item::class, ['menuFactory' => $this->_menuFactoryMock, 'data' => $this->_params] ); @@ -218,15 +213,86 @@ public function testIsAllowedReturnsFalseIfResourceIsNotAvailable() public function testGetChildrenCreatesSubmenuOnFirstCall() { - $menuMock = $this->getMock( - \Magento\Backend\Model\Menu::class, - [], - [$this->getMock(\Psr\Log\LoggerInterface::class)] - ); + $menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false); $this->_menuFactoryMock->expects($this->once())->method('create')->will($this->returnValue($menuMock)); $this->_model->getChildren(); $this->_model->getChildren(); } + + /** + * @param array $data + * @param array $expected + * @dataProvider toArrayDataProvider + */ + public function testToArray(array $data, array $expected) + { + $menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false); + $this->_menuFactoryMock->method('create')->will($this->returnValue($menuMock)); + $menuMock->method('toArray') + ->willReturn($data['sub_menu']); + + $model = $this->objectManager->getObject( + \Magento\Backend\Model\Menu\Item::class, + [ + 'authorization' => $this->_aclMock, + 'scopeConfig' => $this->_scopeConfigMock, + 'menuFactory' => $this->_menuFactoryMock, + 'urlModel' => $this->_urlModelMock, + 'moduleList' => $this->_moduleListMock, + 'moduleManager' => $this->_moduleManager, + 'data' => $data + ] + ); + $this->assertEquals($expected, $model->toArray()); + } + + /** + * @return array + */ + public function toArrayDataProvider() + { + return include __DIR__ . '/../_files/menu_item_data.php'; + } + + /** + * @param array $constructorData + * @param array $populateFromData + * @param array $expected + * @dataProvider populateFromArrayDataProvider + */ + public function testPopulateFromArray( + array $constructorData, + array $populateFromData, + array $expected + ) { + $menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false); + $this->_menuFactoryMock->method('create')->willReturn($menuMock); + $menuMock->method('toArray') + ->willReturn(['submenuArray']); + + $model = $this->objectManager->getObject( + \Magento\Backend\Model\Menu\Item::class, + [ + 'authorization' => $this->_aclMock, + 'scopeConfig' => $this->_scopeConfigMock, + 'menuFactory' => $this->_menuFactoryMock, + 'urlModel' => $this->_urlModelMock, + 'moduleList' => $this->_moduleListMock, + 'moduleManager' => $this->_moduleManager, + 'data' => $constructorData + ] + ); + $model->populateFromArray($populateFromData); + $this->assertEquals($expected, $model->toArray()); + } + + /** + * @return array + */ + public function populateFromArrayDataProvider() + { + return include __DIR__ . '/../_files/menu_item_constructor_data.php'; + } } diff --git a/app/code/Magento/Backend/Test/Unit/Model/MenuBuilderTest.php b/app/code/Magento/Backend/Test/Unit/Model/MenuBuilderTest.php index fc519ded8e860..7d972aa2792e1 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/MenuBuilderTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/MenuBuilderTest.php @@ -1,6 +1,6 @@ objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->_items['item1'] = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); $this->_items['item1']->expects($this->any())->method('getId')->will($this->returnValue('item1')); @@ -35,7 +45,12 @@ protected function setUp() $this->_logger = $this->getMock(\Psr\Log\LoggerInterface::class); - $this->_model = new \Magento\Backend\Model\Menu($this->_logger); + $this->_model = $this->objectManagerHelper->getObject( + \Magento\Backend\Model\Menu::class, + [ + 'logger' => $this->_logger + ] + ); } public function testAdd() @@ -53,7 +68,7 @@ public function testAddDoLogAddAction() public function testAddToItem() { - $subMenu = $this->getMock(\Magento\Backend\Model\Menu::class, [], [$this->_logger]); + $subMenu = $this->getMockBuilder(\Magento\Backend\Model\Menu::class)->disableOriginalConstructor()->getMock(); $subMenu->expects($this->once())->method("add")->with($this->_items['item2']); $this->_items['item1']->expects($this->once())->method("getChildren")->will($this->returnValue($subMenu)); @@ -101,19 +116,29 @@ public function testGet() public function testGetRecursive() { - $menu1 = new \Magento\Backend\Model\Menu($this->_logger); - $menu2 = new \Magento\Backend\Model\Menu($this->_logger); + $menuOne = $this->objectManagerHelper->getObject( + \Magento\Backend\Model\Menu::class, + [ + 'logger' => $this->_logger + ] + ); + $menuTwo = $this->objectManagerHelper->getObject( + \Magento\Backend\Model\Menu::class, + [ + 'logger' => $this->_logger + ] + ); $this->_items['item1']->expects($this->any())->method('hasChildren')->will($this->returnValue(true)); - $this->_items['item1']->expects($this->any())->method('getChildren')->will($this->returnValue($menu1)); + $this->_items['item1']->expects($this->any())->method('getChildren')->will($this->returnValue($menuOne)); $this->_model->add($this->_items['item1']); $this->_items['item2']->expects($this->any())->method('hasChildren')->will($this->returnValue(true)); - $this->_items['item2']->expects($this->any())->method('getChildren')->will($this->returnValue($menu2)); - $menu1->add($this->_items['item2']); + $this->_items['item2']->expects($this->any())->method('getChildren')->will($this->returnValue($menuTwo)); + $menuOne->add($this->_items['item2']); $this->_items['item3']->expects($this->any())->method('hasChildren')->will($this->returnValue(false)); - $menu2->add($this->_items['item3']); + $menuTwo->add($this->_items['item3']); $this->assertEquals($this->_items['item1'], $this->_model->get('item1')); $this->assertEquals($this->_items['item2'], $this->_model->get('item2')); @@ -126,11 +151,7 @@ public function testMove() $this->_model->add($this->_items['item2']); $this->_model->add($this->_items['item3']); - $subMenu = $this->getMock( - \Magento\Backend\Model\Menu::class, - [], - [$this->getMock(\Psr\Log\LoggerInterface::class)] - ); + $subMenu = $this->getMockBuilder(\Magento\Backend\Model\Menu::class)->disableOriginalConstructor()->getMock(); $subMenu->expects($this->once())->method("add")->with($this->_items['item3']); $this->_items['item1']->expects($this->once())->method("getChildren")->will($this->returnValue($subMenu)); @@ -179,11 +200,7 @@ public function testRemoveRemovesMenuItem() public function testRemoveRemovesMenuItemRecursively() { - $menuMock = $this->getMock( - \Magento\Backend\Model\Menu::class, - [], - [$this->getMock(\Psr\Log\LoggerInterface::class)] - ); + $menuMock = $this->getMockBuilder(\Magento\Backend\Model\Menu::class)->disableOriginalConstructor()->getMock(); $menuMock->expects($this->once())->method('remove')->with($this->equalTo('item2')); $this->_items['item1']->expects($this->any())->method('hasChildren')->will($this->returnValue(true)); @@ -214,7 +231,12 @@ public function testReorderReordersItemOnItsLevel() { $this->_logger->expects($this->any())->method('log'); - $subMenu = new \Magento\Backend\Model\Menu($this->_logger); + $subMenu = $this->objectManagerHelper->getObject( + \Magento\Backend\Model\Menu::class, + [ + 'logger' => $this->_logger + ] + ); $this->_items['item1']->expects($this->any())->method("hasChildren")->will($this->returnValue(true)); @@ -285,11 +307,11 @@ public function testMultipleIterationsWorkProperly() $items[] = $item->getId(); } - $items2 = []; + $itemsTwo = []; foreach ($this->_model as $item) { - $items2[] = $item->getId(); + $itemsTwo[] = $item->getId(); } - $this->assertEquals($items, $items2); + $this->assertEquals($items, $itemsTwo); } /** @@ -307,10 +329,10 @@ public function testNestedLoop() 'item3' => ['item1', 'item2', 'item3'], ]; $actual = []; - foreach ($this->_model as $valLoop1) { - $keyLevel1 = $valLoop1->getId(); - foreach ($this->_model as $valLoop2) { - $actual[$keyLevel1][] = $valLoop2->getId(); + foreach ($this->_model as $valLoopOne) { + $keyLevelOne = $valLoopOne->getId(); + foreach ($this->_model as $valLoopTwo) { + $actual[$keyLevelOne][] = $valLoopTwo->getId(); } } $this->assertEquals($expected, $actual); @@ -318,7 +340,45 @@ public function testNestedLoop() public function testSerialize() { - $this->assertNotEmpty($this->_model->serialize()); - $this->_model->add($this->_items['item1']); + $serializerMock = $this->getMock(SerializerInterface::class); + $serializerMock->expects($this->once()) + ->method('serialize') + ->with([['arrayData']]) + ->willReturn('serializedString'); + $menu = $this->objectManagerHelper->getObject( + \Magento\Backend\Model\Menu::class, + [ + 'logger' => $this->_logger, + 'serializer' => $serializerMock, + ] + ); + $itemMock = $this->getMock(\Magento\Backend\Model\Menu\Item::class, [], [], '', false); + $itemMock->expects($this->any())->method('getId')->will($this->returnValue('item1')); + $itemMock->expects($this->once()) + ->method('toArray') + ->willReturn(['arrayData']); + $menu->add($itemMock); + $this->assertEquals('serializedString', $menu->serialize()); + } + + public function testUnserialize() + { + $serializerMock = $this->getMock(SerializerInterface::class); + $serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn([['unserializedData']]); + $menuItemFactoryMock = $this->getMock(Factory::class, [], [], '', false); + $menuItemFactoryMock->expects($this->once()) + ->method('create') + ->with(['unserializedData']); + $menu = $this->objectManagerHelper->getObject( + \Magento\Backend\Model\Menu::class, + [ + 'logger' => $this->_logger, + 'serializer' => $serializerMock, + 'menuItemFactory' => $menuItemFactoryMock, + ] + ); + $menu->unserialize('serializedString'); } } diff --git a/app/code/Magento/Backend/Test/Unit/Model/Session/AdminConfigTest.php b/app/code/Magento/Backend/Test/Unit/Model/Session/AdminConfigTest.php index fa5b86df391c3..53817fc21a955 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/Session/AdminConfigTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/Session/AdminConfigTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->customerRepositoryMock = $this->getMockForAbstractClass( \Magento\Customer\Api\CustomerRepositoryInterface::class, [], @@ -197,13 +198,6 @@ protected function setUp() ); $this->quoteFactoryMock = $this->getMock(\Magento\Quote\Model\QuoteFactory::class, ['create'], [], '', false); - $this->cartManagementMock = $this->getMock( - \Magento\Quote\Api\CartManagementInterface::class, - [], - [], - '', - false - ); $this->quote = $this->getMock( \Magento\Backend\Model\Session\Quote::class, @@ -226,10 +220,6 @@ protected function setUp() 'quoteFactory' => $this->quoteFactoryMock ] ); - - $this->prepareObjectManager([ - [\Magento\Quote\Api\CartManagementInterface::class, $this->cartManagementMock] - ]); } /** @@ -416,19 +406,4 @@ public function getQuoteDataProvider() 'customer ids same' => [66, 66, 'never'], ]; } - - /** - * @param array $map - * @deprecated - */ - private function prepareObjectManager($map) - { - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); - $objectManagerMock->expects($this->any())->method('getInstance')->willReturnSelf(); - $objectManagerMock->expects($this->any())->method('get')->will($this->returnValueMap($map)); - $reflectionClass = new \ReflectionClass(\Magento\Framework\App\ObjectManager::class); - $reflectionProperty = $reflectionClass->getProperty('_instance'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($objectManagerMock); - } } diff --git a/app/code/Magento/Backend/Test/Unit/Model/Translate/Inline/ConfigTest.php b/app/code/Magento/Backend/Test/Unit/Model/Translate/Inline/ConfigTest.php index fbffdd4fdb16c..dbb03d249519f 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/Translate/Inline/ConfigTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/Translate/Inline/ConfigTest.php @@ -1,6 +1,6 @@ _menuMock = $this->getMock( - \Magento\Backend\Model\Menu::class, - [], - [$this->getMock(\Psr\Log\LoggerInterface::class)] - ); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->_menuMock = $this->getMock(\Magento\Backend\Model\Menu::class, [], [], '', false); $this->_menuConfigMock = $this->getMock(\Magento\Backend\Model\Menu\Config::class, [], [], '', false); $this->_menuConfigMock->expects($this->any())->method('getMenu')->will($this->returnValue($this->_menuMock)); @@ -141,25 +137,21 @@ protected function setUp() false, false ); - $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->_encryptor = $this->getMock(\Magento\Framework\Encryption\Encryptor::class, null, [], '', false); - $this->_paramsResolverMock = $this->getMock( + $routeParamsResolver = $this->getMock(\Magento\Framework\Url\RouteParamsResolver::class, [], [], '', false); + $this->routeParamsResolverFactoryMock = $this->getMock( \Magento\Framework\Url\RouteParamsResolverFactory::class, [], [], '', false ); - $this->_paramsResolverMock->expects( - $this->any() - )->method( - 'create' - )->will( - $this->returnValue( - $this->getMock(\Magento\Framework\Url\RouteParamsResolver::class, [], [], '', false) - ) - ); - $this->_model = $helper->getObject( + $this->routeParamsResolverFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($routeParamsResolver); + /** @var HostChecker|\PHPUnit_Framework_MockObject_MockObject $hostCheckerMock */ + $hostCheckerMock = $this->getMock(HostChecker::class, [], [], '', false); + $this->_model = $objectManager->getObject( \Magento\Backend\Model\Url::class, [ 'scopeConfig' => $this->_scopeConfigMock, @@ -168,31 +160,10 @@ protected function setUp() 'menuConfig' => $this->_menuConfigMock, 'authSession' => $this->_authSessionMock, 'encryptor' => $this->_encryptor, - 'routeParamsResolverFactory' => $this->_paramsResolverMock + 'routeParamsResolverFactory' => $this->routeParamsResolverFactoryMock, + 'hostChecker' => $hostCheckerMock ] ); - $this->_paramsResolverMock->expects( - $this->any() - )->method( - 'create' - )->will( - $this->returnValue( - $this->getMock(\Magento\Framework\Url\RouteParamsResolver::class, [], [], '', false) - ) - ); - $this->_model = $helper->getObject( - \Magento\Backend\Model\Url::class, - [ - 'scopeConfig' => $this->_scopeConfigMock, - 'backendHelper' => $helperMock, - 'formKey' => $this->_formKey, - 'menuConfig' => $this->_menuConfigMock, - 'authSession' => $this->_authSessionMock, - 'encryptor' => $this->_encryptor, - 'routeParamsResolverFactory' => $this->_paramsResolverMock - ] - ); - $this->_requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false); $this->_model->setRequest($this->_requestMock); } @@ -262,7 +233,7 @@ public function testGetAreaFrontName() [ 'backendHelper' => $helperMock, 'authSession' => $this->_authSessionMock, - 'routeParamsResolverFactory' => $this->_paramsResolverMock + 'routeParamsResolverFactory' => $this->routeParamsResolverFactoryMock ] ); $urlModel->getAreaFrontName(); diff --git a/app/code/Magento/Backend/Test/Unit/Model/View/Layout/ConditionPoolTest.php b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/ConditionPoolTest.php new file mode 100644 index 0000000000000..46cea7665cc3b --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/ConditionPoolTest.php @@ -0,0 +1,65 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); + $this->conditionPool = $objectManager->getObject( + ConditionPool::class, + [ + 'conditions' => [ + 'condition-1' => 'Condition_1', + 'condition-2' => 'Condition_2', + ], + 'objectManager' => $this->objectManagerMock + ] + ); + } + + public function testGetCondition() + { + $this->objectManagerMock->expects($this->once()) + ->method('get') + ->with('Condition_1') + ->willReturn('Condition1Instance'); + $this->assertEquals( + 'Condition1Instance', + $this->conditionPool->getCondition('condition-1') + ); + } + + /** + * @expectedException \Magento\Framework\Exception\InputException + */ + public function testGetConditionUnknownCondition() + { + $this->conditionPool->getCondition('condition-3'); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Model/View/Layout/Filter/AclTest.php b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/Filter/AclTest.php index 820704c859769..9eb02e568439f 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/View/Layout/Filter/AclTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/Filter/AclTest.php @@ -1,28 +1,47 @@ authorizationMock = $this->getMockBuilder(\Magento\Framework\AuthorizationInterface::class) + $this->authorizationMock = $this->getMockBuilder(AuthorizationInterface::class) + ->getMock(); + $this->structureManager = $this->getMockBuilder(StructureManager::class) ->getMock(); - $this->model = new \Magento\Backend\Model\View\Layout\Filter\Acl($this->authorizationMock); + $objectManager = new ObjectManager($this); + $this->model = $objectManager->getObject( + Acl::class, + [ + 'authorization' => $this->authorizationMock + ] + ); + $objectManager->setBackwardCompatibleProperty($this->model, 'structureManager', $this->structureManager); } public function testFilterAclElements() @@ -86,28 +105,8 @@ public function testFilterAclElements() ] ); - $structureMock->expects($this->exactly(3)) - ->method('getChildren') - ->willReturnMap( - [ - ['element_2', ['element_2_child' => []]], - ['element_2_child', []], - ['element_3', []], - ] - ); - - $scheduledStructureMock->expects($this->exactly(3)) - ->method('unsetElement') - ->willReturnMap( - [ - ['element_2', null], - ['element_2_child', null], - ['element_3', null], - ] - ); - - $structureMock->expects($this->exactly(2)) - ->method('unsetElement') + $this->structureManager->expects($this->exactly(2)) + ->method('removeElement') ->willReturnMap( [ ['element_2', true, true], diff --git a/app/code/Magento/Backend/Test/Unit/Model/View/Layout/Filter/ConditionTest.php b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/Filter/ConditionTest.php new file mode 100644 index 0000000000000..dacfbac3c4aa7 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/Filter/ConditionTest.php @@ -0,0 +1,139 @@ +structureManagerMock = $this->getMockBuilder(StructureManager::class) + ->getMock(); + $this->structureMock = $this->getMockBuilder(Structure::class) + ->disableOriginalConstructor() + ->getMock(); + $this->scheduledStructureMock = $this->getMockBuilder(ScheduledStructure::class) + ->getMock(); + $this->conditionPoolMock = $this->getMockBuilder(ConditionPool::class) + ->disableOriginalConstructor() + ->getMock(); + $this->conditionMock = $this->getMockBuilder(ConditionInterface::class) + ->getMock(); + $objectManager = new ObjectManager($this); + + $this->filter = $objectManager->getObject( + Condition::class, + [ + 'structureManager' => $this->structureManagerMock, + 'conditionPool' => $this->conditionPoolMock + ] + ); + } + + private function getStructureData() + { + return [ + 'element_0' => [ + 0 => '', + 1 => [ + 'attributes' => [ + 'name' => 'element_0', + ], + ], + ], + 'element_1' => [ + 0 => '', + 1 => [ + 'attributes' => [ + 'name' => 'element_1', + 'condition' => 'TestCondition1', + ], + ], + ], + 'element_2' => [ + 0 => '', + 1 => [ + 'attributes' => [ + 'name' => 'element_2', + 'condition' => 'TestCondition2', + ], + ], + ], + 'element_3' => [ + 0 => '', + 1 => [ + 'attributes' => [ + 'name' => 'element_3', + 'acl' => 'acl_non_authorised', + ], + ], + ], + ]; + } + + public function testFilterElement() + { + $this->scheduledStructureMock->expects($this->once()) + ->method('getElements') + ->willReturn($this->getStructureData()); + $this->conditionPoolMock->expects($this->exactly(2)) + ->method('getCondition') + ->willReturnMap( + [ + ['TestCondition1', $this->conditionMock], + ['TestCondition2', $this->conditionMock] + ] + ); + $this->conditionMock->expects($this->at(0)) + ->method('validate') + ->willReturn(false); + $this->conditionMock->expects($this->at(1)) + ->method('validate') + ->willReturn(true); + $this->structureManagerMock->expects($this->once()) + ->method('removeElement') + ->with($this->scheduledStructureMock, $this->structureMock, 'element_1') + ->willReturn(true); + $this->assertTrue($this->filter->filterElement($this->scheduledStructureMock, $this->structureMock)); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Model/View/Layout/FilterTest.php b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/FilterTest.php new file mode 100644 index 0000000000000..0a51c9c1c56f3 --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/FilterTest.php @@ -0,0 +1,65 @@ +someFilterMock = $this->getMockBuilder(FilterInterface::class) + ->getMock(); + $this->structureMock = $this->getMockBuilder(Structure::class) + ->disableOriginalConstructor() + ->getMock(); + $this->scheduledStructureMock = $this->getMockBuilder(ScheduledStructure::class) + ->getMock(); + $objectManager = new ObjectManager($this); + $this->filter = $objectManager->getObject( + Filter::class, + [ + 'filters' => + [ + 'filter1' => $this->someFilterMock + ] + ] + ); + } + + public function testFilterElement() + { + $this->someFilterMock->expects($this->once()) + ->method('filterElement') + ->with($this->scheduledStructureMock, $this->structureMock); + $this->assertTrue($this->filter->filterElement($this->scheduledStructureMock, $this->structureMock)); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Model/View/Layout/StructureManagerTest.php b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/StructureManagerTest.php new file mode 100644 index 0000000000000..a5a9055c0d03f --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Model/View/Layout/StructureManagerTest.php @@ -0,0 +1,87 @@ +structureMock = $this->getMockBuilder(Structure::class) + ->disableOriginalConstructor() + ->getMock(); + $this->scheduledStructureMock = $this->getMockBuilder(ScheduledStructure::class) + ->disableOriginalConstructor() + ->getMock(); + $this->structureManager = $objectManager->getObject(StructureManager::class); + } + + public function testRemoveElement() + { + $this->structureMock->expects($this->exactly(3)) + ->method('getChildren') + ->willReturnMap( + [ + [ + 'element-0', [ + 'element-1' => [], + 'element-2' => [] + ] + ], + [ + 'element-1', [] + ], + [ + 'element-2', [] + ] + ] + ); + $this->scheduledStructureMock->expects($this->exactly(3)) + ->method('unsetElement') + ->willReturnMap( + [ + ['element-0', true], + ['element-1', true], + ['element-2', true] + ] + ); + $this->structureMock->expects($this->once()) + ->method('unsetElement') + ->with('element-0'); + $this->assertTrue( + $this->structureManager->removeElement( + $this->scheduledStructureMock, + $this->structureMock, + 'element-0', + false + ) + ); + } +} diff --git a/app/code/Magento/Backend/Test/Unit/Model/View/Result/PageTest.php b/app/code/Magento/Backend/Test/Unit/Model/View/Result/PageTest.php index f88692029c159..3f1a6834f25a9 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/View/Result/PageTest.php +++ b/app/code/Magento/Backend/Test/Unit/Model/View/Result/PageTest.php @@ -1,6 +1,6 @@ [ + [], + [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + [ + 'parent_id' => null, + 'module_name' => 'Magento_Backend', + 'sort_index' => null, + 'depends_on_config' => 'system/config/isEnabled', + 'id' => 'item', + 'resource' => 'Magento_Config::config', + 'path' => '', + 'action' => '/system/config', + 'depends_on_module' => 'Magento_Backend', + 'tooltip' => 'Item tooltip', + 'title' => 'Item Title', + 'sub_menu' => null, + 'target' => null + ], + ], + 'data without submenu to constructor' => [ + [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'depends_on_config' => null, + 'id' => '5', + 'resource' => null, + 'path' => null, + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => null, + 'title' => null, + 'sub_menu' => [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + ], + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'depends_on_config' => null, + 'id' => '5', + 'resource' => null, + 'path' => '', + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => '', + 'title' => null, + 'sub_menu' => ['submenuArray'], + 'target' => null + ], + ], + 'data with submenu to constructor' => [ + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'depends_on_config' => null, + 'id' => '5', + 'resource' => null, + 'path' => null, + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => null, + 'title' => null, + 'sub_menu' => [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + ], + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'sub_menu' => [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + ], + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'depends_on_config' => null, + 'id' => null, + 'resource' => null, + 'path' => '', + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => '', + 'title' => null, + 'sub_menu' => ['submenuArray'], + 'target' => null + ], + ] +]; diff --git a/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_data.php b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_data.php new file mode 100644 index 0000000000000..bc336aad5783d --- /dev/null +++ b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_item_data.php @@ -0,0 +1,121 @@ + [ + [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + 'sub_menu' => null, + ], + [ + 'parent_id' => null, + 'module_name' => 'Magento_Backend', + 'sort_index' => null, + 'depends_on_config' => 'system/config/isEnabled', + 'id' => 'item', + 'resource' => 'Magento_Config::config', + 'path' => '', + 'action' => '/system/config', + 'depends_on_module' => 'Magento_Backend', + 'tooltip' => 'Item tooltip', + 'title' => 'Item Title', + 'sub_menu' => null, + 'target' => null + ] + ], + 'with submenu' => [ + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'depends_on_config' => null, + 'id' => '5', + 'resource' => null, + 'path' => null, + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => null, + 'title' => null, + 'sub_menu' => [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + ], + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'depends_on_config' => null, + 'id' => '5', + 'resource' => null, + 'path' => null, + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => '', + 'title' => null, + 'sub_menu' => [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + 'target' => null + ] + ], + 'small set of data' => [ + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'sub_menu' => [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + ], + [ + 'parent_id' => '1', + 'module_name' => 'Magento_Module1', + 'sort_index' => '50', + 'depends_on_config' => null, + 'id' => null, + 'resource' => null, + 'path' => '', + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => '', + 'title' => null, + 'sub_menu' => [ + 'id' => 'item', + 'title' => 'Item Title', + 'action' => '/system/config', + 'resource' => 'Magento_Config::config', + 'depends_on_module' => 'Magento_Backend', + 'depends_on_config' => 'system/config/isEnabled', + 'tooltip' => 'Item tooltip', + ], + 'target' => null + ] + ] +]; diff --git a/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.php b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.php index ad86dea88ef08..c5213cdab9d87 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.php +++ b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.xml b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.xml index 55ed5a90d8025..e7ac5aec547d2 100644 --- a/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.xml +++ b/app/code/Magento/Backend/Test/Unit/Model/_files/menu_merged.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/Test/Unit/Setup/ConfigOptionsListTest.php b/app/code/Magento/Backend/Test/Unit/Setup/ConfigOptionsListTest.php index d7a8de1012b82..dd90832aa38b4 100644 --- a/app/code/Magento/Backend/Test/Unit/Setup/ConfigOptionsListTest.php +++ b/app/code/Magento/Backend/Test/Unit/Setup/ConfigOptionsListTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/etc/adminhtml/di.xml b/app/code/Magento/Backend/etc/adminhtml/di.xml index fcf2cc02e9fb9..9488d35adcc87 100644 --- a/app/code/Magento/Backend/etc/adminhtml/di.xml +++ b/app/code/Magento/Backend/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ @@ -141,4 +141,12 @@ + + + + Magento\Config\Model\Config\Structure\ElementVisibilityInterface::HIDDEN + Magento\Config\Model\Config\Structure\ElementVisibilityInterface::DISABLED + + + diff --git a/app/code/Magento/Backend/etc/adminhtml/menu.xml b/app/code/Magento/Backend/etc/adminhtml/menu.xml index 1a754291cb47c..d7d57b7953c77 100644 --- a/app/code/Magento/Backend/etc/adminhtml/menu.xml +++ b/app/code/Magento/Backend/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/etc/adminhtml/routes.xml b/app/code/Magento/Backend/etc/adminhtml/routes.xml index 232ac5222daea..2f3857c91c5c0 100644 --- a/app/code/Magento/Backend/etc/adminhtml/routes.xml +++ b/app/code/Magento/Backend/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml index 7297f3a6c2299..fc6c8df551913 100644 --- a/app/code/Magento/Backend/etc/adminhtml/system.xml +++ b/app/code/Magento/Backend/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ @@ -16,7 +16,7 @@ -
    +
    advanced Magento_Backend::advanced @@ -198,7 +198,7 @@ Magento_Config::config_general - + Magento\Directory\Model\Config\Source\Country 1 diff --git a/app/code/Magento/Backend/etc/config.xml b/app/code/Magento/Backend/etc/config.xml index 459dd377e36ba..1d347c7471725 100644 --- a/app/code/Magento/Backend/etc/config.xml +++ b/app/code/Magento/Backend/etc/config.xml @@ -1,7 +1,7 @@ @@ -11,6 +11,9 @@ + + 1 + diff --git a/app/code/Magento/Backend/etc/crontab.xml b/app/code/Magento/Backend/etc/crontab.xml index 0c7e18e977549..4f6450a7226ae 100644 --- a/app/code/Magento/Backend/etc/crontab.xml +++ b/app/code/Magento/Backend/etc/crontab.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/etc/di.xml b/app/code/Magento/Backend/etc/di.xml index 8b52d08da48fb..8894f2293fa35 100644 --- a/app/code/Magento/Backend/etc/di.xml +++ b/app/code/Magento/Backend/etc/di.xml @@ -1,7 +1,7 @@ @@ -14,6 +14,7 @@ + @@ -180,37 +181,36 @@ - + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + + - - - design/theme/theme_id - theme - Magento\Theme\Model\Design\Backend\Theme - true - - - design/theme/ua_regexp - desing_rule - Magento\Theme\Model\Design\Backend\Exceptions - - - design/pagination/pagination_frame - other_settings/pagination - - - design/pagination/pagination_frame_skip - other_settings/pagination - - - design/pagination/anchor_text_for_previous - other_settings/pagination - - - design/pagination/anchor_text_for_next - other_settings/pagination - + + Magento\Backend\Model\View\Layout\Filter\Acl + Magento\Backend\Model\View\Layout\Filter\Condition + + + Magento\Backend\Block\MenuItemChecker + Magento\Backend\Block\AnchorRenderer + + diff --git a/app/code/Magento/Backend/etc/menu.xsd b/app/code/Magento/Backend/etc/menu.xsd index 05df67a5e2bbd..f7a22103e2e90 100644 --- a/app/code/Magento/Backend/etc/menu.xsd +++ b/app/code/Magento/Backend/etc/menu.xsd @@ -1,7 +1,7 @@ @@ -31,6 +31,7 @@ + @@ -51,6 +52,7 @@ + diff --git a/app/code/Magento/Backend/etc/module.xml b/app/code/Magento/Backend/etc/module.xml index db6b19407c73b..b7f188e78d34e 100644 --- a/app/code/Magento/Backend/etc/module.xml +++ b/app/code/Magento/Backend/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/etc/webapi.xml b/app/code/Magento/Backend/etc/webapi.xml index d01bbafa8e676..14d4dccc78cbe 100644 --- a/app/code/Magento/Backend/etc/webapi.xml +++ b/app/code/Magento/Backend/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/registration.php b/app/code/Magento/Backend/registration.php index 5e9d9fe4dabe7..fac71f545151f 100644 --- a/app/code/Magento/Backend/registration.php +++ b/app/code/Magento/Backend/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_auth_login.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_auth_login.xml index d8462aeedfa1a..bb7370b3317a4 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_auth_login.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_auth_login.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml index 3e61fec077c6e..e4f6fbea1cd29 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml @@ -1,7 +1,7 @@ @@ -23,10 +23,12 @@ Enable adminhtml/*/massEnable + Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker Disable adminhtml/*/massDisable + Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker Refresh @@ -48,6 +50,7 @@ 180 left 0 + true @@ -57,6 +60,7 @@ text left 0 + true diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_index.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_index.xml index 8edb476a2b555..77ba8f6f39824 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_index.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersmost.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersmost.xml index 39b3db77d505e..31b3ff2c44bc1 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersmost.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersmost.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersnewest.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersnewest.xml index ce83aa64faafb..ce4e20140eb54 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersnewest.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_customersnewest.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_index.xml index 8b36caac55b82..b353b81aa1b7c 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_productsviewed.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_productsviewed.xml index d55194f4dbb43..4621d83dc6753 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_productsviewed.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_dashboard_productsviewed.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_denied.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_denied.xml index e8754242dfd2f..fac9407cc3298 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_denied.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_denied.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_noroute.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_noroute.xml index 4872a39a16e45..598bdf490e8a5 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_noroute.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_noroute.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_account_index.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_account_index.xml index 581f6d2ee5972..dfc27d5e6b5e0 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_account_index.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_account_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_edit.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_edit.xml index 4f5d3a778a120..91469c51e06c9 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_edit.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid.xml index 4a0c8a711f5ea..bda7f3883adce 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml index 3d2c4dff37228..a39aee9813286 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_index.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_index.xml index 8ae928a3cadcf..7412c983cff8b 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_index.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml index 320ce474bc392..0521a87831663 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_index.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_index.xml index 64d7968bd1772..2abd830f5fa37 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_index.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/default.xml b/app/code/Magento/Backend/view/adminhtml/layout/default.xml index 9db902fb13294..ea98fd70740aa 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/default.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/editor.xml b/app/code/Magento/Backend/view/adminhtml/layout/editor.xml index 9109e54ac357b..2c34667c0502e 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/editor.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/editor.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/empty.xml b/app/code/Magento/Backend/view/adminhtml/layout/empty.xml index 7509438df2553..e01b48cc71b11 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/empty.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/empty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/formkey.xml b/app/code/Magento/Backend/view/adminhtml/layout/formkey.xml index 50b1784b33210..6ba9743703ed4 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/formkey.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/formkey.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/overlay_popup.xml b/app/code/Magento/Backend/view/adminhtml/layout/overlay_popup.xml index 67304406b201b..8a48fcca66c0e 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/overlay_popup.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/overlay_popup.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/layout/popup.xml b/app/code/Magento/Backend/view/adminhtml/layout/popup.xml index 825094937cd9d..dd65940af81e5 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/popup.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/popup.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/requirejs-config.js b/app/code/Magento/Backend/view/adminhtml/requirejs-config.js index 9c1350ea268cb..2703ea79738b7 100644 --- a/app/code/Magento/Backend/view/adminhtml/requirejs-config.js +++ b/app/code/Magento/Backend/view/adminhtml/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*eslint no-unused-vars: 0*/ diff --git a/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml b/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml index 7ff08dcc32422..32910c9978d2d 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml b/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml index 0968047053bc5..1716af3ec14c4 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/admin/login.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/templates/admin/overlay_popup.phtml b/app/code/Magento/Backend/view/adminhtml/templates/admin/overlay_popup.phtml index ab29376b3b573..e95b063599daa 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/admin/overlay_popup.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/admin/overlay_popup.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml index e93b143e039c8..aeac3fd33248c 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/media/uploader.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/templates/page/notices.phtml b/app/code/Magento/Backend/view/adminhtml/templates/page/notices.phtml index 987afc07df489..b4e7c2d7f50a8 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/page/notices.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/page/notices.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/templates/system/design/index.phtml b/app/code/Magento/Backend/view/adminhtml/templates/system/design/index.phtml index 3b5748da54823..2cdb9f451a86f 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/system/design/index.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/system/design/index.phtml @@ -1,6 +1,6 @@ @@ -61,11 +61,14 @@ CountryModel.prototype = { if (applyCountryElement && applyCountryElement.id) { var specifCountryElement = $(applyCountryElement.id.replace(/sallowspecific/, 'specificcountry')); var showMethodElement = $(applyCountryElement.id.replace(/sallowspecific/, 'showmethod')); + // 'Use Default' checkbox of the related county list UI element + var useDefaultElement = document.getElementById(specifCountryElement.id + '_inherit'); + //var specifErrMsgElement = $(applyCountryElement.id.replace(/sallowspecific/, 'specificerrmsg')); if (specifCountryElement) { if (applyCountryElement.value == 1) { - //if specific country element selected - specifCountryElement.enable(); + // enable related country select only if its 'Use Default' checkbox is absent or is unchecked + specifCountryElement.disabled = useDefaultElement ? useDefaultElement.checked : false; if (showMethodElement) { this.showElement(showMethodElement.up(1)); } diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/accordion.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/accordion.phtml index 52e4d895c1dc1..060ee67e9a7b2 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/accordion.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/accordion.phtml @@ -1,6 +1,6 @@ getExportButtonHtml() ?> - \ No newline at end of file + diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml index 62ff8d2752362..838e22f16493a 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/ui_component/design_config_listing.xml b/app/code/Magento/Backend/view/adminhtml/ui_component/design_config_listing.xml index c72e5f3c9079e..c299f217c8df7 100644 --- a/app/code/Magento/Backend/view/adminhtml/ui_component/design_config_listing.xml +++ b/app/code/Magento/Backend/view/adminhtml/ui_component/design_config_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/bootstrap/editor.js b/app/code/Magento/Backend/view/adminhtml/web/js/bootstrap/editor.js index 08ff14f84f660..de003bb3b8d08 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/js/bootstrap/editor.js +++ b/app/code/Magento/Backend/view/adminhtml/web/js/bootstrap/editor.js @@ -1,9 +1,9 @@ /** * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ require([ "Magento_Variable/variables", "mage/adminhtml/browser" -]); \ No newline at end of file +]); diff --git a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js index 18f44da26109a..fe7c8dd7cb800 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js +++ b/app/code/Magento/Backend/view/adminhtml/web/js/media-uploader.js @@ -1,6 +1,6 @@ /** * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global byteConvert*/ diff --git a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/cells/action-delete.html b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/cells/action-delete.html index 44c460825b45d..e60fc8c2c238e 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/cells/action-delete.html +++ b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/cells/action-delete.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html index 63a3196ff3385..8714e443faf28 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html +++ b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html @@ -1,6 +1,6 @@ @@ -34,7 +34,7 @@
    -
    +
    @@ -51,10 +51,10 @@ + diff --git a/app/code/Magento/Backend/view/adminhtml/web/template/form/element/helper/fallback-reset-link.html b/app/code/Magento/Backend/view/adminhtml/web/template/form/element/helper/fallback-reset-link.html index 25b584f89f9fa..f788dbb6fbe20 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/template/form/element/helper/fallback-reset-link.html +++ b/app/code/Magento/Backend/view/adminhtml/web/template/form/element/helper/fallback-reset-link.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backup/Block/Adminhtml/Backup.php b/app/code/Magento/Backup/Block/Adminhtml/Backup.php index 354dca87a79a9..0aa4f8833e9ea 100644 --- a/app/code/Magento/Backup/Block/Adminhtml/Backup.php +++ b/app/code/Magento/Backup/Block/Adminhtml/Backup.php @@ -1,6 +1,6 @@ _view->loadLayout(); - $this->_view->renderLayout(); + return $this->resultFactory->create(ResultFactory::TYPE_PAGE); } } diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php index d845a28569f63..f784e507e96b1 100644 --- a/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Index.php @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/etc/adminhtml/menu.xml b/app/code/Magento/Backup/etc/adminhtml/menu.xml index 812b1cb9d0df8..32c2936697fac 100644 --- a/app/code/Magento/Backup/etc/adminhtml/menu.xml +++ b/app/code/Magento/Backup/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/etc/adminhtml/routes.xml b/app/code/Magento/Backup/etc/adminhtml/routes.xml index 3e0e606439eed..232c0ca0f9d6a 100644 --- a/app/code/Magento/Backup/etc/adminhtml/routes.xml +++ b/app/code/Magento/Backup/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/etc/adminhtml/system.xml b/app/code/Magento/Backup/etc/adminhtml/system.xml index 69e15030ad6a7..325395826df15 100644 --- a/app/code/Magento/Backup/etc/adminhtml/system.xml +++ b/app/code/Magento/Backup/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/etc/crontab.xml b/app/code/Magento/Backup/etc/crontab.xml index a0a1fdbdf2a15..150751eb94a1f 100644 --- a/app/code/Magento/Backup/etc/crontab.xml +++ b/app/code/Magento/Backup/etc/crontab.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/etc/di.xml b/app/code/Magento/Backup/etc/di.xml index f9371f4a249bf..fc9c5bb2ff025 100644 --- a/app/code/Magento/Backup/etc/di.xml +++ b/app/code/Magento/Backup/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/etc/module.xml b/app/code/Magento/Backup/etc/module.xml index 9edced27b2247..9f4fe8da7ac1d 100644 --- a/app/code/Magento/Backup/etc/module.xml +++ b/app/code/Magento/Backup/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/registration.php b/app/code/Magento/Backup/registration.php index c158dddf70a65..d429ad8208552 100644 --- a/app/code/Magento/Backup/registration.php +++ b/app/code/Magento/Backup/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_grid.xml b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_grid.xml index 1f6e1cbec7f10..03b4aa4a7f4ad 100644 --- a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_grid.xml +++ b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_index.xml b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_index.xml index 42c3d766b6997..242534d006e37 100644 --- a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_index.xml +++ b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml b/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml index c3ac897edd8e5..597651f8329e3 100644 --- a/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml +++ b/app/code/Magento/Backup/view/adminhtml/templates/backup/dialogs.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Backup/view/adminhtml/templates/backup/list.phtml b/app/code/Magento/Backup/view/adminhtml/templates/backup/list.phtml index 0fff82609ed11..ace0931b60428 100644 --- a/app/code/Magento/Backup/view/adminhtml/templates/backup/list.phtml +++ b/app/code/Magento/Backup/view/adminhtml/templates/backup/list.phtml @@ -1,6 +1,6 @@ serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(Json::class); + } + /** * Get list of available dynamic descriptors keys * @var array @@ -45,7 +72,7 @@ class Config extends \Magento\Payment\Gateway\Config\Config */ public function getCountrySpecificCardTypeConfig() { - $countriesCardTypes = unserialize($this->getValue(self::KEY_COUNTRY_CREDIT_CARD)); + $countriesCardTypes = $this->serializer->unserialize($this->getValue(self::KEY_COUNTRY_CREDIT_CARD)); return is_array($countriesCardTypes) ? $countriesCardTypes : []; } diff --git a/app/code/Magento/Braintree/Gateway/Config/PayPal/Config.php b/app/code/Magento/Braintree/Gateway/Config/PayPal/Config.php index f94c6abfd773b..3f34afd0717db 100644 --- a/app/code/Magento/Braintree/Gateway/Config/PayPal/Config.php +++ b/app/code/Magento/Braintree/Gateway/Config/PayPal/Config.php @@ -1,6 +1,6 @@ paymentTokenFactory = $paymentTokenFactory; $this->paymentExtensionFactory = $paymentExtensionFactory; $this->config = $config; $this->subjectReader = $subjectReader; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\SerializerInterface::class); } /** @@ -133,7 +142,7 @@ private function getExpirationDate(Transaction $transaction) */ private function convertDetailsToJSON($details) { - $json = \Zend_Json::encode($details); + $json = $this->serializer->serialize($details); return $json ? $json : '{}'; } diff --git a/app/code/Magento/Braintree/Gateway/Response/VoidHandler.php b/app/code/Magento/Braintree/Gateway/Response/VoidHandler.php index 5fc173af704a8..c3534d4a906e4 100644 --- a/app/code/Magento/Braintree/Gateway/Response/VoidHandler.php +++ b/app/code/Magento/Braintree/Gateway/Response/VoidHandler.php @@ -1,6 +1,6 @@ collectionFactory = $factory; $this->countryConfig = $countryConfig; } diff --git a/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php b/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php index 12e7cd8f532cc..c53d9e3f5ba8c 100644 --- a/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php +++ b/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php @@ -1,6 +1,6 @@ mathRandom = $mathRandom; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(Json::class); parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); } @@ -68,7 +78,7 @@ public function beforeSave() $result[$country] = $data['cc_types']; } } - $this->setValue(serialize($result)); + $this->setValue($this->serializer->serialize($result)); return $this; } @@ -79,7 +89,7 @@ public function beforeSave() */ public function afterLoad() { - $value = unserialize($this->getValue()); + $value = $this->serializer->unserialize($this->getValue()); if (is_array($value)) { $value = $this->encodeArrayFieldValue($value); $this->setValue($value); diff --git a/app/code/Magento/Braintree/Model/Paypal/Helper/AbstractHelper.php b/app/code/Magento/Braintree/Model/Paypal/Helper/AbstractHelper.php index ad72fcf8a424b..0a5583d465f68 100644 --- a/app/code/Magento/Braintree/Model/Paypal/Helper/AbstractHelper.php +++ b/app/code/Magento/Braintree/Model/Paypal/Helper/AbstractHelper.php @@ -1,6 +1,6 @@ componentFactory = $componentFactory; + $this->urlBuilder = $urlBuilder; + $this->config = $config; + } + + /** + * @inheritdoc + */ + public function getComponentForToken(PaymentTokenInterface $paymentToken) + { + $data = json_decode($paymentToken->getTokenDetails() ?: '{}', true); + $data['icon'] = $this->config->getPayPalIcon(); + $component = $this->componentFactory->create( + [ + 'config' => [ + 'code' => PayPalConfigProvider::PAYPAL_VAULT_CODE, + 'nonceUrl' => $this->getNonceRetrieveUrl(), + TokenUiComponentProviderInterface::COMPONENT_DETAILS => $data, + TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH => $paymentToken->getPublicHash(), + 'template' => 'Magento_Braintree::form/paypal/vault.phtml' + ], + 'name' => Template::class + ] + ); + + return $component; + } + + /** + * Get url to retrieve payment method nonce + * @return string + */ + private function getNonceRetrieveUrl() + { + return $this->urlBuilder->getUrl(ConfigProvider::CODE . '/payment/getnonce', ['_secure' => true]); + } +} diff --git a/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php b/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php index 6cfc96ea23d0d..b2c6b53e2538a 100644 --- a/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php +++ b/app/code/Magento/Braintree/Model/Ui/Adminhtml/TokenUiComponentProvider.php @@ -1,6 +1,6 @@ componentFactory->create( [ 'config' => [ + 'code' => ConfigProvider::CC_VAULT_CODE, 'nonceUrl' => $this->getNonceRetrieveUrl(), TokenUiComponentProviderInterface::COMPONENT_DETAILS => $data, TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH => $paymentToken->getPublicHash(), diff --git a/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php b/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php index 76788c3c14510..d96ee2ba58e98 100644 --- a/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php +++ b/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php @@ -1,6 +1,6 @@ fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; + } + + /** + * Upgrades data for Braintree module + * + * @param ModuleDataSetupInterface $setup + * @param ModuleContextInterface $context + * @return void + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + if (version_compare($context->getVersion(), '2.0.1', '<')) { + $this->convertSerializedDataToJson($setup); + } + } + + /** + * Upgrade data to version 2.0.1, converts row data in the core_config_data table that uses the path + * payment/braintree/countrycreditcard from serialized to JSON + * + * @param ModuleDataSetupInterface $setup + * @return void + */ + private function convertSerializedDataToJson(ModuleDataSetupInterface $setup) + { + $fieldDataConverter = $this->fieldDataConverterFactory->create( + \Magento\Framework\DB\DataConverter\SerializedToJson::class + ); + + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'path' => ['payment/braintree/countrycreditcard'] + ] + ] + ); + + $fieldDataConverter->convert( + $setup->getConnection(), + $setup->getTable('core_config_data'), + 'config_id', + 'value', + $queryModifier + ); + } +} diff --git a/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php b/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php index e6c7ce59d0e29..4d2b2cba3faaf 100644 --- a/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php @@ -1,6 +1,6 @@ scopeConfigMock = $this->getMock(ScopeConfigInterface::class); + $this->serializerMock = $this->getMock(Json::class); - $this->model = new Config($this->scopeConfigMock, self::METHOD_CODE); + $objectManager = new ObjectManager($this); + $this->model = $objectManager->getObject( + Config::class, + [ + 'scopeConfig' => $this->scopeConfigMock, + 'methodCode' => self::METHOD_CODE, + 'serializer' => $this->serializerMock + ] + ); } /** - * @param string $value + * @param string $encodedValue + * @param string|array $value * @param array $expected * @dataProvider getCountrySpecificCardTypeConfigDataProvider */ - public function testGetCountrySpecificCardTypeConfig($value, $expected) + public function testGetCountrySpecificCardTypeConfig($encodedValue, $value, array $expected) { $this->scopeConfigMock->expects(static::once()) ->method('getValue') ->with($this->getPath(Config::KEY_COUNTRY_CREDIT_CARD), ScopeInterface::SCOPE_STORE, null) + ->willReturn($encodedValue); + + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($encodedValue) ->willReturn($value); static::assertEquals( @@ -58,11 +80,13 @@ public function testGetCountrySpecificCardTypeConfig($value, $expected) public function getCountrySpecificCardTypeConfigDataProvider() { return [ - [ - serialize(['GB' => ['VI', 'AE'], 'US' => ['DI', 'JCB']]), + 'valid data' => [ + '{"GB":["VI","AE"],"US":["DI","JCB"]}', + ['GB' => ['VI', 'AE'], 'US' => ['DI', 'JCB']], ['GB' => ['VI', 'AE'], 'US' => ['DI', 'JCB']] ], - [ + 'non-array value' => [ + '""', '', [] ] @@ -146,12 +170,20 @@ public function getCcTypesMapperDataProvider() /** * @covers \Magento\Braintree\Gateway\Config\Config::getCountryAvailableCardTypes * @dataProvider getCountrySpecificCardTypeConfigDataProvider + * @param string $encodedData + * @param string|array $data + * @param array $countryData */ - public function testCountryAvailableCardTypes($data, $countryData) + public function testCountryAvailableCardTypes($encodedData, $data, array $countryData) { $this->scopeConfigMock->expects(static::any()) ->method('getValue') ->with($this->getPath(Config::KEY_COUNTRY_CREDIT_CARD), ScopeInterface::SCOPE_STORE, null) + ->willReturn($encodedData); + + $this->serializerMock->expects($this->any()) + ->method('unserialize') + ->with($encodedData) ->willReturn($data); foreach ($countryData as $countryId => $types) { diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Helper/SubjectReaderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Helper/SubjectReaderTest.php index 02192c819daf5..f4056c8abb3f3 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Helper/SubjectReaderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Helper/SubjectReaderTest.php @@ -1,6 +1,6 @@ method('getCctypesMapper') ->willReturn($mapperArray); + $this->serializer = $this->getMock( + \Magento\Framework\Serialize\SerializerInterface::class, + [], + [], + '', + false + ); + $this->paymentHandler = new VaultDetailsHandler( $this->paymentTokenFactory, $this->paymentExtensionFactory, $this->config, - $this->subjectReader + $this->subjectReader, + $this->serializer ); } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VoidHandlerTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VoidHandlerTest.php index f0ec710e13827..51971e077f91a 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VoidHandlerTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Response/VoidHandlerTest.php @@ -1,6 +1,6 @@ resourceMock = $this->getMockForAbstractClass(AbstractResource::class); $this->mathRandomMock = $this->getMockBuilder(Random::class) ->disableOriginalConstructor() ->getMock(); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class); $this->objectManager = new ObjectManager($this); $this->model = $this->objectManager->getObject( @@ -50,18 +56,28 @@ protected function setUp() [ 'mathRandom' => $this->mathRandomMock, 'resource' => $this->resourceMock, + 'serializer' => $this->serializerMock ] ); } /** * @dataProvider beforeSaveDataProvider + * @param array $value + * @param array $expectedValue + * @param string $encodedValue */ - public function testBeforeSave($value, $expectedValue) + public function testBeforeSave(array $value, array $expectedValue, $encodedValue) { $this->model->setValue($value); + + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($expectedValue) + ->willReturn($encodedValue); + $this->model->beforeSave(); - $this->assertEquals($expectedValue, $this->model->getValue()); + $this->assertEquals($encodedValue, $this->model->getValue()); } /** @@ -73,11 +89,13 @@ public function beforeSaveDataProvider() return [ 'empty_value' => [ 'value' => [], - 'expected' => serialize([]), + 'expected' => [], + 'encoded' => '[]' ], 'not_array' => [ 'value' => ['US'], - 'expected' => serialize([]), + 'expected' => [], + 'encoded' => '[]' ], 'array_with_invalid_format' => [ 'value' => [ @@ -85,7 +103,8 @@ public function beforeSaveDataProvider() 'country_id' => 'US', ], ], - 'expected' => serialize([]), + 'expected' => [], + 'encoded' => '[]' ], 'array_with_two_countries' => [ 'value' => [ @@ -99,12 +118,11 @@ public function beforeSaveDataProvider() ], '__empty' => "", ], - 'expected' => serialize( - [ - 'AF' => ['AE', 'VI'], - 'US' => ['AE', 'VI', 'MA'], - ] - ), + 'expected' => [ + 'AF' => ['AE', 'VI'], + 'US' => ['AE', 'VI', 'MA'], + ], + 'encoded' => '{"AF":["AE","VI"],"US":["AE","VI","MA"]}' ], 'array_with_two_same_countries' => [ 'value' => [ @@ -122,29 +140,38 @@ public function beforeSaveDataProvider() ], '__empty' => "", ], - 'expected' => serialize( - [ - 'AF' => ['AE', 'VI'], - 'US' => ['AE', 'VI', 'MA', 'OT'], - ] - ), + 'expected' => [ + 'AF' => ['AE', 'VI'], + 'US' => ['AE', 'VI', 'MA', 'OT'], + ], + 'encoded' => '{"AF":["AE","VI"],"US":["AE","VI","MA","OT"]}' ], ]; } /** * @dataProvider afterLoadDataProvider + * @param string $encodedValue + * @param array|null $value + * @param array $hashData + * @param array|null $expected */ - public function testAfterLoad($value, $hashData, $expected) + public function testAfterLoad($encodedValue, $value, array $hashData, $expected) { - $this->model->setValue($value); + $this->model->setValue($encodedValue); $index = 0; foreach ($hashData as $hash) { $this->mathRandomMock->expects(static::at($index)) ->method('getUniqueHash') ->willReturn($hash); - $index ++; + $index++; } + + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($encodedValue) + ->willReturn($value); + $this->model->afterLoad(); $this->assertEquals($expected, $this->model->getValue()); } @@ -157,34 +184,35 @@ public function afterLoadDataProvider() { return [ 'empty' => [ - 'value' => serialize([]), + 'encoded' => '[]', + 'value' => [], 'randomHash' => [], - 'expected' => [], + 'expected' => [] ], 'null' => [ + 'encoded' => '', 'value' => null, 'randomHash' => [], - 'expected' => null, + 'expected' => null ], - 'valid_data' => [ - 'value' => serialize( - [ - 'US' => ['AE', 'VI', 'MA'], - 'AF' => ['AE', 'MA'], - ] - ), + 'valid data' => [ + 'encoded' => '{"US":["AE","VI","MA"],"AF":["AE","MA"]}', + 'value' => [ + 'US' => ['AE', 'VI', 'MA'], + 'AF' => ['AE', 'MA'] + ], 'randomHash' => ['hash_1', 'hash_2'], 'expected' => [ 'hash_1' => [ 'country_id' => 'US', - 'cc_types' => ['AE', 'VI', 'MA'], + 'cc_types' => ['AE', 'VI', 'MA'] ], 'hash_2' => [ 'country_id' => 'AF', - 'cc_types' => ['AE', 'MA'], - ], + 'cc_types' => ['AE', 'MA'] + ] ] - ], + ] ]; } } diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Adminhtml/System/Config/CountryTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Adminhtml/System/Config/CountryTest.php index 3beaf139e5bc5..ccb8e7e8f6e17 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Adminhtml/System/Config/CountryTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Adminhtml/System/Config/CountryTest.php @@ -1,6 +1,6 @@ componentFactory = $this->getMockBuilder(TokenUiComponentInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->urlBuilder = $this->getMock(UrlInterface::class); + + $this->config = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->setMethods(['getPayPalIcon']) + ->getMock(); + + $this->tokenUiComponentProvider = new TokenUiComponentProvider( + $this->componentFactory, + $this->urlBuilder, + $this->config + ); + } + + /** + * @covers \Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider::getComponentForToken + */ + public function testGetComponentForToken() + { + $nonceUrl = 'https://payment/adminhtml/nonce/url'; + $payerEmail = 'john.doe@test.com'; + $icon = [ + 'url' => 'https://payment/adminhtml/icon.png', + 'width' => 48, + 'height' => 32 + ]; + + $expected = [ + 'code' => 'vault', + 'nonceUrl' => $nonceUrl, + 'details' => [ + 'payerEmail' => $payerEmail, + 'icon' => $icon + ], + 'template' => 'vault.phtml' + ]; + + $this->config->expects(static::once()) + ->method('getPayPalIcon') + ->willReturn($icon); + + $paymentToken = $this->getMock(PaymentTokenInterface::class); + $paymentToken->expects(static::once()) + ->method('getTokenDetails') + ->willReturn('{"payerEmail":" ' . $payerEmail . '"}'); + $paymentToken->expects(static::once()) + ->method('getPublicHash') + ->willReturn('cmk32dl21l'); + + $this->urlBuilder->expects(static::once()) + ->method('getUrl') + ->willReturn($nonceUrl); + + $tokenComponent = $this->getMock(TokenUiComponentInterface::class); + $tokenComponent->expects(static::once()) + ->method('getConfig') + ->willReturn($expected); + + $this->componentFactory->expects(static::once()) + ->method('create') + ->willReturn($tokenComponent); + + $component = $this->tokenUiComponentProvider->getComponentForToken($paymentToken); + static::assertEquals($tokenComponent, $component); + static::assertEquals($expected, $component->getConfig()); + } +} diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php index d1665c71804cf..d39cd32425013 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/Adminhtml/TokenUiComponentProviderTest.php @@ -1,16 +1,16 @@ 'vault', 'nonceUrl' => $nonceUrl, 'details' => [ 'type' => $type, diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php index 04846f369eba9..1adc43a1ecd28 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Braintree/etc/adminhtml/di.xml b/app/code/Magento/Braintree/etc/adminhtml/di.xml index f252b977f20bd..c91b4edbd2e70 100644 --- a/app/code/Magento/Braintree/etc/adminhtml/di.xml +++ b/app/code/Magento/Braintree/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ @@ -47,6 +47,7 @@ Magento\Braintree\Model\Ui\Adminhtml\TokenUiComponentProvider + Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider diff --git a/app/code/Magento/Braintree/etc/adminhtml/menu.xml b/app/code/Magento/Braintree/etc/adminhtml/menu.xml index ed73aa20cdb6f..43d12aa0bb995 100644 --- a/app/code/Magento/Braintree/etc/adminhtml/menu.xml +++ b/app/code/Magento/Braintree/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/etc/adminhtml/routes.xml b/app/code/Magento/Braintree/etc/adminhtml/routes.xml index 698664f02e6a3..0991aef948541 100644 --- a/app/code/Magento/Braintree/etc/adminhtml/routes.xml +++ b/app/code/Magento/Braintree/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/etc/adminhtml/system.xml b/app/code/Magento/Braintree/etc/adminhtml/system.xml index 5f62a9d7cf192..ef3cdc3f51256 100644 --- a/app/code/Magento/Braintree/etc/adminhtml/system.xml +++ b/app/code/Magento/Braintree/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ @@ -33,7 +33,7 @@ - + Magento\Config\Model\Config\Source\Yesno payment/braintree_cc_vault/active @@ -155,7 +155,7 @@ It is recommended to set this value to "PayPal" per store views. - + Magento\Config\Model\Config\Source\Yesno payment/braintree_paypal_vault/active diff --git a/app/code/Magento/Braintree/etc/config.xml b/app/code/Magento/Braintree/etc/config.xml index 095a8419c8529..eaa233da109ce 100644 --- a/app/code/Magento/Braintree/etc/config.xml +++ b/app/code/Magento/Braintree/etc/config.xml @@ -1,7 +1,7 @@ @@ -71,7 +71,8 @@ BraintreePayPalVaultFacade - Vault Token (Braintree PayPal) + Stored Accounts (Braintree PayPal) + 1 diff --git a/app/code/Magento/Braintree/etc/di.xml b/app/code/Magento/Braintree/etc/di.xml index 849a3039fc361..6f596cc4a8daf 100644 --- a/app/code/Magento/Braintree/etc/di.xml +++ b/app/code/Magento/Braintree/etc/di.xml @@ -1,7 +1,7 @@ @@ -22,6 +22,7 @@ Magento\Braintree\Model\Ui\PayPal\ConfigProvider::PAYPAL_CODE BraintreePayPalInfo BraintreePayPalValueHandlerPool + BraintreePayPalValidatorPool BraintreePayPalCommandPool @@ -364,7 +365,7 @@ - + @@ -451,7 +452,7 @@ - + @@ -474,7 +475,7 @@ - + Magento\Braintree\Gateway\Config\Config @@ -487,6 +488,22 @@ + + + + + + Magento\Braintree\Gateway\Config\PayPal\Config + + + + + + BraintreePayPalCountryValidator + + + + @@ -527,4 +544,16 @@ + + + + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Braintree/etc/events.xml b/app/code/Magento/Braintree/etc/events.xml index 6d76a626d15bd..2bf95bdbad178 100644 --- a/app/code/Magento/Braintree/etc/events.xml +++ b/app/code/Magento/Braintree/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/etc/frontend/di.xml b/app/code/Magento/Braintree/etc/frontend/di.xml index cdd56e236a72b..781f985b4b3a8 100644 --- a/app/code/Magento/Braintree/etc/frontend/di.xml +++ b/app/code/Magento/Braintree/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/etc/frontend/events.xml b/app/code/Magento/Braintree/etc/frontend/events.xml index df1db1420b5a1..e1bff1a20b238 100644 --- a/app/code/Magento/Braintree/etc/frontend/events.xml +++ b/app/code/Magento/Braintree/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/etc/frontend/routes.xml b/app/code/Magento/Braintree/etc/frontend/routes.xml index 7ec5a0c1b097c..ad8b484ca30d6 100644 --- a/app/code/Magento/Braintree/etc/frontend/routes.xml +++ b/app/code/Magento/Braintree/etc/frontend/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/etc/frontend/sections.xml b/app/code/Magento/Braintree/etc/frontend/sections.xml index f87695a624730..add86f4cdb5cc 100644 --- a/app/code/Magento/Braintree/etc/frontend/sections.xml +++ b/app/code/Magento/Braintree/etc/frontend/sections.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/etc/module.xml b/app/code/Magento/Braintree/etc/module.xml index 2b7759fc7843b..b7d0957c2ef6d 100644 --- a/app/code/Magento/Braintree/etc/module.xml +++ b/app/code/Magento/Braintree/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Braintree/registration.php b/app/code/Magento/Braintree/registration.php index 33f9f68a4197b..d56ac32c07c96 100644 --- a/app/code/Magento/Braintree/registration.php +++ b/app/code/Magento/Braintree/registration.php @@ -1,6 +1,6 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Braintree/view/adminhtml/layout/braintree_report_index.xml b/app/code/Magento/Braintree/view/adminhtml/layout/braintree_report_index.xml index 30c334cd09464..396f86b903fd5 100644 --- a/app/code/Magento/Braintree/view/adminhtml/layout/braintree_report_index.xml +++ b/app/code/Magento/Braintree/view/adminhtml/layout/braintree_report_index.xml @@ -1,7 +1,7 @@ @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml index 571c5ededeb99..b5ce1fc9c6792 100644 --- a/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml +++ b/app/code/Magento/Braintree/view/adminhtml/layout/sales_order_create_index.xml @@ -1,7 +1,7 @@ @@ -18,6 +18,10 @@ braintree_cc_vault Magento_Vault::form/vault.phtml + + braintree_paypal_vault + Magento_Vault::form/vault.phtml + @@ -18,6 +18,10 @@ braintree_cc_vault Magento_Vault::form/vault.phtml + + braintree_paypal_vault + Magento_Vault::form/vault.phtml + - \ No newline at end of file + diff --git a/app/code/Magento/Braintree/view/adminhtml/templates/form/cc.phtml b/app/code/Magento/Braintree/view/adminhtml/templates/form/cc.phtml index cd2fbcf3fec7a..50076da1a851f 100644 --- a/app/code/Magento/Braintree/view/adminhtml/templates/form/cc.phtml +++ b/app/code/Magento/Braintree/view/adminhtml/templates/form/cc.phtml @@ -1,6 +1,6 @@ getData(TokenUiComponentProviderInterface::COMPONENT_DETAILS); +$icon = $details['icon']; +$id = $block->escapeHtml($block->getData('id')); +?> +
    ", + "nonceUrl": "escapeUrl($block->getData('nonceUrl')); ?>" + } + }' id="payment_" class="admin__field"> +
    + + + escapeHtml($details['payerEmail']); ?> +
    +
    diff --git a/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml b/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml index 3811461884725..5414be0a571e9 100644 --- a/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml +++ b/app/code/Magento/Braintree/view/adminhtml/templates/form/vault.phtml @@ -1,13 +1,13 @@ getData('details'); +$details = $block->getData(TokenUiComponentProviderInterface::COMPONENT_DETAILS); $icon = $block->getData('icons')[$details['type']]; $id = $block->escapeHtml($block->getData('id')); ?> @@ -15,6 +15,7 @@ $id = $block->escapeHtml($block->getData('id')); "Magento_Braintree/js/vault": { "container": "payment_", "publicHash": "escapeHtml($block->getData(TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH)); ?>", + "code": "escapeHtml($block->getData('code')); ?>", "nonceUrl": "escapeUrl($block->getData('nonceUrl')); ?>" } }' id="payment_" class="admin__field"> diff --git a/app/code/Magento/Braintree/view/adminhtml/templates/grid/tooltip.phtml b/app/code/Magento/Braintree/view/adminhtml/templates/grid/tooltip.phtml index 7a07fe648f315..34c109e2d69f8 100644 --- a/app/code/Magento/Braintree/view/adminhtml/templates/grid/tooltip.phtml +++ b/app/code/Magento/Braintree/view/adminhtml/templates/grid/tooltip.phtml @@ -1,6 +1,6 @@ escapeHtml($block->getCode()); payment = new Braintree(config); }); //]]> - \ No newline at end of file + diff --git a/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml b/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml index 031ddca7a8707..7613bbcfd4081 100644 --- a/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml +++ b/app/code/Magento/Braintree/view/adminhtml/ui_component/braintree_report.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js b/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js index 93b2f9831ef35..2457e3582a15e 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*browser:true*/ diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/grid/filters/status.html b/app/code/Magento/Braintree/view/adminhtml/web/js/grid/filters/status.html index 68c1dbcee8f45..f69cbcc619846 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/grid/filters/status.html +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/grid/filters/status.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/grid/provider.js b/app/code/Magento/Braintree/view/adminhtml/web/js/grid/provider.js index ff0f8408b4079..8b1380f6029be 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/grid/provider.js +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/grid/provider.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js index fcff173e7fcd4..541542c83bc8f 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/vault.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*browser:true*/ @@ -14,7 +14,8 @@ define([ return Class.extend({ defaults: { $selector: null, - selector: 'edit_form' + selector: 'edit_form', + $container: null }, /** @@ -25,17 +26,18 @@ define([ var self = this; self.$selector = $('#' + self.selector); + self.$container = $('#' + self.container); self.$selector.on( - 'setVaultNotActive', + 'setVaultNotActive.' + self.getCode(), function () { - self.$selector.off('submitOrder.braintree_vault'); + self.$selector.off('submitOrder.' + self.getCode()); } ); - this._super(); + self._super(); - this.initEventHandlers(); + self.initEventHandlers(); - return this; + return self; }, /** @@ -43,14 +45,14 @@ define([ * @returns {String} */ getCode: function () { - return 'braintree'; + return this.code; }, /** * Init event handlers */ initEventHandlers: function () { - $('#' + this.container).find('[name="payment[token_switcher]"]') + $(this.$container).find('[name="payment[token_switcher]"]') .on('click', this.selectPaymentMethod.bind(this)); }, @@ -66,7 +68,7 @@ define([ * Enable form event listeners */ enableEventListeners: function () { - this.$selector.on('submitOrder.braintree_vault', this.submitOrder.bind(this)); + this.$selector.on('submitOrder.' + this.getCode(), this.submitOrder.bind(this)); }, /** @@ -129,7 +131,7 @@ define([ this.createPublicHashSelector(); this.$selector.find('[name="payment[public_hash]"]').val(this.publicHash); - this.$selector.find('#braintree_nonce').val(nonce); + this.$container.find('#' + this.getNonceSelectorName()).val(nonce); }, /** @@ -138,16 +140,16 @@ define([ createPublicHashSelector: function () { var $input; - if (this.$selector.find('#braintree_nonce').size() === 0) { + if (this.$container.find('#' + this.getNonceSelectorName()).size() === 0) { $input = $('').attr( { type: 'hidden', - id: 'braintree_nonce', + id: this.getNonceSelectorName(), name: 'payment[payment_method_nonce]' } ); - $input.appendTo(this.$selector); + $input.appendTo(this.$container); $input.prop('disabled', false); } }, @@ -160,6 +162,14 @@ define([ alert({ content: message }); + }, + + /** + * Get selector name for nonce input + * @returns {String} + */ + getNonceSelectorName: function () { + return 'nonce_' + this.getCode(); } }); }); diff --git a/app/code/Magento/Braintree/view/adminhtml/web/styles.css b/app/code/Magento/Braintree/view/adminhtml/web/styles.css index 31f48cd0b28df..19a4f794fb428 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/styles.css +++ b/app/code/Magento/Braintree/view/adminhtml/web/styles.css @@ -1,8 +1,8 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -.braintree-section .heading {display: inline-block; background: url("images/braintree_logo.png") no-repeat 0 50% / 18rem auto; padding-left: 20rem;} -.braintree-section .button-container {display: inline-block; float: right;} -.braintree-section .config-alt {background: url("images/braintree_allinone.png") no-repeat scroll 0 0 / 100% auto; height: 28px; margin: 0.5rem 0 0; width: 230px;} \ No newline at end of file +.braintree-section .heading {background: url("images/braintree_logo.png") no-repeat 0 50% / 18rem auto; padding-left: 20rem;} +.braintree-section .button-container {float: right;} +.braintree-section .config-alt {background: url("images/braintree_allinone.png") no-repeat scroll 0 0 / 100% auto; height: 28px; margin: 0.5rem 0 0; width: 230px;} diff --git a/app/code/Magento/Braintree/view/base/web/js/validator.js b/app/code/Magento/Braintree/view/base/web/js/validator.js index 8c878840ca10c..931774aaffa2d 100644 --- a/app/code/Magento/Braintree/view/base/web/js/validator.js +++ b/app/code/Magento/Braintree/view/base/web/js/validator.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*browser:true*/ diff --git a/app/code/Magento/Braintree/view/frontend/layout/braintree_paypal_review.xml b/app/code/Magento/Braintree/view/frontend/layout/braintree_paypal_review.xml index 19b7a795c2dc2..a5125861a048f 100644 --- a/app/code/Magento/Braintree/view/frontend/layout/braintree_paypal_review.xml +++ b/app/code/Magento/Braintree/view/frontend/layout/braintree_paypal_review.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml index a6b5b8795c46b..872cb7d51ce1f 100644 --- a/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Braintree/view/frontend/layout/checkout_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/view/frontend/layout/vault_cards_listaction.xml b/app/code/Magento/Braintree/view/frontend/layout/vault_cards_listaction.xml index c8cd4e3cc4085..1ab68abf1976d 100644 --- a/app/code/Magento/Braintree/view/frontend/layout/vault_cards_listaction.xml +++ b/app/code/Magento/Braintree/view/frontend/layout/vault_cards_listaction.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Braintree/view/frontend/requirejs-config.js b/app/code/Magento/Braintree/view/frontend/requirejs-config.js index 76391a81fe663..e12a4dd87043e 100644 --- a/app/code/Magento/Braintree/view/frontend/requirejs-config.js +++ b/app/code/Magento/Braintree/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml b/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml index 35cb4617ec9ed..5fc4bf83cab28 100644 --- a/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml +++ b/app/code/Magento/Braintree/view/frontend/templates/paypal/button.phtml @@ -1,6 +1,6 @@ @@ -109,8 +109,8 @@ -
    -
    \ No newline at end of file +
    diff --git a/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal/vault.html b/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal/vault.html index eef06f048cdc1..28cd3ebb2f2d1 100644 --- a/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal/vault.html +++ b/app/code/Magento/Braintree/view/frontend/web/template/payment/paypal/vault.html @@ -1,6 +1,6 @@ @@ -44,4 +44,4 @@
    - \ No newline at end of file + diff --git a/app/code/Magento/Bundle/Api/Data/BundleOptionInterface.php b/app/code/Magento/Bundle/Api/Data/BundleOptionInterface.php index a10d131c000ce..5ef6c2971b18b 100644 --- a/app/code/Magento/Bundle/Api/Data/BundleOptionInterface.php +++ b/app/code/Magento/Bundle/Api/Data/BundleOptionInterface.php @@ -1,6 +1,6 @@ serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(Json::class); + + parent::__construct($context, $stockRegistry, $stockConfiguration, $registry, $data); + } + /** * Truncate string * @@ -153,7 +183,7 @@ public function getSelectionAttributes($item) $options = $item->getOrderItem()->getProductOptions(); } if (isset($options['bundle_selection_attributes'])) { - return unserialize($options['bundle_selection_attributes']); + return $this->serializer->unserialize($options['bundle_selection_attributes']); } return null; } diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php index 01e122a56b52d..a3214b4dadd5f 100644 --- a/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php +++ b/app/code/Magento/Bundle/Block/Adminhtml/Sales/Order/View/Items/Renderer.php @@ -1,17 +1,59 @@ serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(Json::class); + + parent::__construct( + $context, + $stockRegistry, + $stockConfiguration, + $registry, + $messageHelper, + $checkoutHelper, + $data + ); + } + /** * Truncate string * @@ -110,7 +152,7 @@ public function getSelectionAttributes($item) $options = $item->getOrderItem()->getProductOptions(); } if (isset($options['bundle_selection_attributes'])) { - return unserialize($options['bundle_selection_attributes']); + return $this->serializer->unserialize($options['bundle_selection_attributes']); } return null; } diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/Price.php b/app/code/Magento/Bundle/Block/Catalog/Product/Price.php index 01521e2f06f78..32bfe71786e86 100644 --- a/app/code/Magento/Bundle/Block/Catalog/Product/Price.php +++ b/app/code/Magento/Bundle/Block/Catalog/Product/Price.php @@ -1,6 +1,6 @@ catalogRuleProcessor === null) { + $this->catalogRuleProcessor = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor::class); + } + + return $this->catalogRuleProcessor; + } + + /** + * Returns the bundle product options + * Will return cached options data if the product options are already initialized + * In a case when $stripSelection parameter is true will reload stored bundle selections collection from DB + * + * @param bool $stripSelection * @return array */ - public function getOptions() + public function getOptions($stripSelection = false) { if (!$this->options) { $product = $this->getProduct(); + /** @var \Magento\Bundle\Model\Product\Type $typeInstance */ $typeInstance = $product->getTypeInstance(); $typeInstance->setStoreFilter($product->getStoreId(), $product); @@ -93,10 +118,12 @@ public function getOptions() $typeInstance->getOptionsIds($product), $product ); + $this->getCatalogRuleProcessor()->addPriceData($selectionCollection); + $selectionCollection->addTierPriceData(); $this->options = $optionCollection->appendSelections( $selectionCollection, - false, + $stripSelection, $this->catalogProduct->getSkipSaleableCheck() ); } diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php index 5f0fc28b940d9..af3b3d6b41613 100644 --- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php +++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php @@ -1,6 +1,6 @@ serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(Json::class); + + parent::__construct($context, $string, $productOptionFactory, $data); + } + /** * @param mixed $item * @return bool @@ -100,7 +128,7 @@ public function getSelectionAttributes($item) $options = $item->getOrderItem()->getProductOptions(); } if (isset($options['bundle_selection_attributes'])) { - return unserialize($options['bundle_selection_attributes']); + return $this->serializer->unserialize($options['bundle_selection_attributes']); } return null; } diff --git a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Product/Edit/AddAttributeToTemplate.php b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Product/Edit/AddAttributeToTemplate.php index de6ef2abfa05d..d37f4ff77fd91 100644 --- a/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Product/Edit/AddAttributeToTemplate.php +++ b/app/code/Magento/Bundle/Controller/Adminhtml/Bundle/Product/Edit/AddAttributeToTemplate.php @@ -1,7 +1,7 @@ productConfiguration = $productConfiguration; $this->pricingHelper = $pricingHelper; $this->escaper = $escaper; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($context); } @@ -113,7 +124,10 @@ public function getBundleOptions(ItemInterface $item) // get bundle options $optionsQuoteItemOption = $item->getOptionByCode('bundle_option_ids'); - $bundleOptionsIds = $optionsQuoteItemOption ? unserialize($optionsQuoteItemOption->getValue()) : []; + $bundleOptionsIds = $optionsQuoteItemOption + ? $this->serializer->unserialize($optionsQuoteItemOption->getValue()) + : []; + if ($bundleOptionsIds) { /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */ $optionsCollection = $typeInstance->getOptionsByIds($bundleOptionsIds, $product); @@ -121,7 +135,7 @@ public function getBundleOptions(ItemInterface $item) // get and add bundle selections collection $selectionsQuoteItemOption = $item->getOptionByCode('bundle_selection_ids'); - $bundleSelectionIds = unserialize($selectionsQuoteItemOption->getValue()); + $bundleSelectionIds = $this->serializer->unserialize($selectionsQuoteItemOption->getValue()); if (!empty($bundleSelectionIds)) { $selectionsCollection = $typeInstance->getSelectionsByIds($bundleSelectionIds, $product); diff --git a/app/code/Magento/Bundle/Helper/Data.php b/app/code/Magento/Bundle/Helper/Data.php index a12b3700f9e8e..051e2f913e11b 100644 --- a/app/code/Magento/Bundle/Helper/Data.php +++ b/app/code/Magento/Bundle/Helper/Data.php @@ -1,6 +1,6 @@ _catalogData = $catalogData; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct( $ruleFactory, $storeManager, @@ -154,7 +164,7 @@ protected function getBundleSelectionIds(\Magento\Catalog\Model\Product $product { $customOption = $product->getCustomOption('bundle_selection_ids'); if ($customOption) { - $selectionIds = unserialize($customOption->getValue()); + $selectionIds = $this->serializer->unserialize($customOption->getValue()); if (!empty($selectionIds) && is_array($selectionIds)) { return $selectionIds; } @@ -533,6 +543,10 @@ public function getTierPrice($qty, $product) $prevGroup = $allCustomersGroupId; foreach ($prices as $price) { + if (empty($price['percentage_value'])) { + // can use only percentage tier price + continue; + } if ($price['cust_group'] != $custGroup && $price['cust_group'] != $allCustomersGroupId) { // tier not for current customer group nor is for all groups continue; @@ -553,8 +567,8 @@ public function getTierPrice($qty, $product) continue; } - if ($price['website_price'] > $prevPrice) { - $prevPrice = $price['website_price']; + if ($price['percentage_value'] > $prevPrice) { + $prevPrice = $price['percentage_value']; $prevQty = $price['price_qty']; $prevGroup = $price['cust_group']; } diff --git a/app/code/Magento/Bundle/Model/Product/ReadHandler.php b/app/code/Magento/Bundle/Model/Product/ReadHandler.php index f14300f927c75..1ef5fe706074c 100644 --- a/app/code/Magento/Bundle/Model/Product/ReadHandler.php +++ b/app/code/Magento/Bundle/Model/Product/ReadHandler.php @@ -1,6 +1,6 @@ _catalogProduct = $catalogProduct; $this->_catalogData = $catalogData; @@ -204,6 +208,7 @@ public function __construct( $this->priceCurrency = $priceCurrency; $this->_stockRegistry = $stockRegistry; $this->_stockState = $stockState; + parent::__construct( $catalogProductOption, $eavConfig, @@ -213,7 +218,8 @@ public function __construct( $filesystem, $coreRegistry, $logger, - $productRepository + $productRepository, + $serializer ); } @@ -275,7 +281,7 @@ public function getSku($product) if ($product->hasCustomOptions()) { $customOption = $product->getCustomOption('bundle_selection_ids'); - $selectionIds = unserialize($customOption->getValue()); + $selectionIds = $this->serializer->unserialize($customOption->getValue()); if (!empty($selectionIds)) { $selections = $this->getSelectionsByIds($selectionIds, $product); foreach ($selections->getItems() as $selection) { @@ -303,7 +309,7 @@ public function getWeight($product) if ($product->hasCustomOptions()) { $customOption = $product->getCustomOption('bundle_selection_ids'); - $selectionIds = unserialize($customOption->getValue()); + $selectionIds = $this->serializer->unserialize($customOption->getValue()); $selections = $this->getSelectionsByIds($selectionIds, $product); foreach ($selections->getItems() as $selection) { $qtyOption = $product->getCustomOption('selection_qty_' . $selection->getSelectionId()); @@ -329,7 +335,7 @@ public function isVirtual($product) { if ($product->hasCustomOptions()) { $customOption = $product->getCustomOption('bundle_selection_ids'); - $selectionIds = unserialize($customOption->getValue()); + $selectionIds = $this->serializer->unserialize($customOption->getValue()); $selections = $this->getSelectionsByIds($selectionIds, $product); $virtualCount = 0; foreach ($selections->getItems() as $selection) { @@ -449,30 +455,24 @@ public function getOptionsCollection($product) */ public function getSelectionsCollection($optionIds, $product) { - $keyOptionIds = is_array($optionIds) ? implode('_', $optionIds) : ''; - $key = $this->_keySelectionsCollection . $keyOptionIds; - if (!$product->hasData($key)) { - $storeId = $product->getStoreId(); - $selectionsCollection = $this->_bundleCollection->create() - ->addAttributeToSelect($this->_config->getProductAttributes()) - ->addAttributeToSelect('tax_class_id')//used for calculation item taxes in Bundle with Dynamic Price - ->setFlag('product_children', true) - ->setPositionOrder() - ->addStoreFilter($this->getStoreFilter($product)) - ->setStoreId($storeId) - ->addFilterByRequiredOptions() - ->setOptionIdsFilter($optionIds); - - if (!$this->_catalogData->isPriceGlobal() && $storeId) { - $websiteId = $this->_storeManager->getStore($storeId) - ->getWebsiteId(); - $selectionsCollection->joinPrices($websiteId); - } - - $product->setData($key, $selectionsCollection); + $storeId = $product->getStoreId(); + $selectionsCollection = $this->_bundleCollection->create() + ->addAttributeToSelect($this->_config->getProductAttributes()) + ->addAttributeToSelect('tax_class_id') //used for calculation item taxes in Bundle with Dynamic Price + ->setFlag('product_children', true) + ->setPositionOrder() + ->addStoreFilter($this->getStoreFilter($product)) + ->setStoreId($storeId) + ->addFilterByRequiredOptions() + ->setOptionIdsFilter($optionIds); + + if (!$this->_catalogData->isPriceGlobal() && $storeId) { + $websiteId = $this->_storeManager->getStore($storeId) + ->getWebsiteId(); + $selectionsCollection->joinPrices($websiteId); } - return $product->getData($key); + return $selectionsCollection; } /** @@ -543,42 +543,34 @@ public function isSalable($product) return $product->getData('all_items_salable'); } - $optionCollection = $this->getOptionsCollection($product); + $isSalable = false; + foreach ($this->getOptionsCollection($product)->getItems() as $option) { + $hasSalable = false; - if (!count($optionCollection->getItems())) { - return false; - } - - $requiredOptionIds = []; + $selectionsCollection = $this->_bundleCollection->create(); + $selectionsCollection->addAttributeToSelect('status'); + $selectionsCollection->addQuantityFilter(); + $selectionsCollection->setFlag('product_children', true); + $selectionsCollection->addFilterByRequiredOptions(); + $selectionsCollection->setOptionIdsFilter([$option->getId()]); - foreach ($optionCollection->getItems() as $option) { - if ($option->getRequired()) { - $requiredOptionIds[$option->getId()] = 0; + foreach ($selectionsCollection as $selection) { + if ($selection->isSalable()) { + $hasSalable = true; + break; + } } - } - $selectionCollection = $this->getSelectionsCollection($optionCollection->getAllIds(), $product); + if ($hasSalable) { + $isSalable = true; + } - if (!count($selectionCollection->getItems())) { - return false; - } - $salableSelectionCount = 0; - - foreach ($selectionCollection as $selection) { - /* @var $selection \Magento\Catalog\Model\Product */ - if ($selection->isSalable()) { - $selectionEnoughQty = $this->_stockRegistry->getStockItem($selection->getId()) - ->getManageStock() - ? $selection->getSelectionQty() <= $this->_stockState->getStockQty($selection->getId()) - : $selection->isInStock(); - - if (!$selection->hasSelectionQty() || $selection->getSelectionCanChangeQty() || $selectionEnoughQty) { - $requiredOptionIds[$selection->getOptionId()] = 1; - $salableSelectionCount++; - } + if (!$hasSalable && $option->getRequired()) { + $isSalable = false; + break; } } - $isSalable = array_sum($requiredOptionIds) == count($requiredOptionIds) && $salableSelectionCount; + $product->setData('all_items_salable', $isSalable); return $isSalable; @@ -709,8 +701,14 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p $this->checkIsResult($_result); $result[] = $_result[0]->setParentProductId($product->getId()) - ->addCustomOption('bundle_option_ids', serialize(array_map('intval', $optionIds))) - ->addCustomOption('bundle_selection_attributes', serialize($attributes)); + ->addCustomOption( + 'bundle_option_ids', + $this->serializer->serialize(array_map('intval', $optionIds)) + ) + ->addCustomOption( + 'bundle_selection_attributes', + $this->serializer->serialize($attributes) + ); if ($isStrictProcessMode) { $_result[0]->setCartQty($qty); @@ -727,8 +725,13 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p foreach ($result as $item) { $item->addCustomOption('bundle_identity', $uniqueKey); } - $product->addCustomOption('bundle_option_ids', serialize(array_map('intval', $optionIds))); - $product->addCustomOption('bundle_selection_ids', serialize($selectionIds)); + $product->addCustomOption( + 'bundle_option_ids', + $this->serializer->serialize( + array_map('intval', $optionIds) + ) + ); + $product->addCustomOption('bundle_selection_ids', $this->serializer->serialize($selectionIds)); return $result; } @@ -838,7 +841,10 @@ public function getOptionsByIds($optionIds, $product) $usedOptions = $product->getData($this->_keyUsedOptions); $usedOptionsIds = $product->getData($this->_keyUsedOptionsIds); - if (!$usedOptions || serialize($usedOptionsIds) != serialize($optionIds)) { + if ( + !$usedOptions + || $this->serializer->serialize($usedOptionsIds) != $this->serializer->serialize($optionIds) + ) { $usedOptions = $this->_bundleOption ->create() ->getResourceCollection() @@ -870,10 +876,10 @@ public function getOrderOptions($product) if ($product->hasCustomOptions()) { $customOption = $product->getCustomOption('bundle_option_ids'); - $optionIds = unserialize($customOption->getValue()); + $optionIds = $this->serializer->unserialize($customOption->getValue()); $options = $this->getOptionsByIds($optionIds, $product); $customOption = $product->getCustomOption('bundle_selection_ids'); - $selectionIds = unserialize($customOption->getValue()); + $selectionIds = $this->serializer->unserialize($customOption->getValue()); $selections = $this->getSelectionsByIds($selectionIds, $product); foreach ($selections->getItems() as $selection) { if ($selection->isSalable()) { @@ -1022,10 +1028,10 @@ public function checkProductBuyState($product) $productOptionIds = $this->getOptionsIds($product); $productSelections = $this->getSelectionsCollection($productOptionIds, $product); $selectionIds = $product->getCustomOption('bundle_selection_ids'); - $selectionIds = unserialize($selectionIds->getValue()); + $selectionIds = $this->serializer->unserialize($selectionIds->getValue()); $buyRequest = $product->getCustomOption('info_buyRequest'); - $buyRequest = new \Magento\Framework\DataObject(unserialize($buyRequest->getValue())); - $bundleOption = $buyRequest->getBundleOption(); + $buyRequest = new \Magento\Framework\DataObject($this->serializer->unserialize($buyRequest->getValue())); + $bundleOption = $buyRequest->getBundleOption(); if (empty($bundleOption)) { throw new \Magento\Framework\Exception\LocalizedException($this->getSpecifyOptionMessage()); diff --git a/app/code/Magento/Bundle/Model/ProductOptionProcessor.php b/app/code/Magento/Bundle/Model/ProductOptionProcessor.php index 1221bc335103a..b4c49a1a1edd2 100644 --- a/app/code/Magento/Bundle/Model/ProductOptionProcessor.php +++ b/app/code/Magento/Bundle/Model/ProductOptionProcessor.php @@ -1,6 +1,6 @@ join( ['e' => $this->getTable('catalog_product_entity')], - "i.entity_id=e.$linkField", + "i.entity_id=e.entity_id", [] )->where( 'e.type_id=?', @@ -502,7 +502,7 @@ protected function _prepareTierPriceIndex($entityIds = null) $select = $connection->select()->from( ['tp' => $this->getTable('catalog_product_entity_tier_price')], - [$linkField] + ['e.entity_id'] )->join( ['e' => $this->getTable('catalog_product_entity')], "tp.{$linkField} = e.{$linkField}", @@ -523,11 +523,11 @@ protected function _prepareTierPriceIndex($entityIds = null) )->columns( new \Zend_Db_Expr('MIN(tp.value)') )->group( - ["tp.{$linkField}", 'cg.customer_group_id', 'cw.website_id'] + ['e.entity_id', 'cg.customer_group_id', 'cw.website_id'] ); if (!empty($entityIds)) { - $select->where("tp.{$linkField} IN(?)", $entityIds); + $select->where('e.entity_id IN(?)', $entityIds); } $query = $select->insertFromSelect($this->_getTierPriceIndexTable()); diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php index 86ed5c6a10766..c05c1dc8b7fa2 100644 --- a/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php +++ b/app/code/Magento/Bundle/Model/ResourceModel/Indexer/Stock.php @@ -1,6 +1,6 @@ */ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection { @@ -19,6 +21,23 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection */ protected $_selectionTable; + /** + * @var DataObject + */ + private $itemPrototype = null; + + /** + * @var \Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor + */ + private $catalogRuleProcessor = null; + + /** + * Is website scope prices joined to collection + * + * @var bool + */ + private $websiteScopePriceJoined = false; + /** * Initialize collection * @@ -90,6 +109,8 @@ public function joinPrices($websiteId) 'price_scope' => 'price.website_id' ] ); + $this->websiteScopePriceJoined = true; + return $this; } @@ -131,4 +152,105 @@ public function setPositionOrder() $this->getSelect()->order('selection.position asc')->order('selection.selection_id asc'); return $this; } + + /** + * Add filtering of product then havent enoght stock + * + * @return $this + */ + public function addQuantityFilter() + { + $this->getSelect() + ->joinInner( + ['stock' => $this->getTable('cataloginventory_stock_status')], + 'selection.product_id = stock.product_id', + [] + ) + ->where( + '(selection.selection_can_change_qty or selection.selection_qty <= stock.qty) and stock.stock_status' + ); + return $this; + } + + /** + * @inheritDoc + */ + public function getNewEmptyItem() + { + if (null === $this->itemPrototype) { + $this->itemPrototype = parent::getNewEmptyItem(); + } + return clone $this->itemPrototype; + } + + /** + * Add filter by price + * + * @param \Magento\Catalog\Model\Product $product + * @param bool $searchMin + * @param bool $useRegularPrice + * + * @return $this + */ + public function addPriceFilter($product, $searchMin, $useRegularPrice = false) + { + if ($product->getPriceType() == \Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC) { + $this->addPriceData(); + if ($useRegularPrice) { + $minimalPriceExpression = 'price'; + } else { + $this->getCatalogRuleProcessor()->addPriceData($this, 'selection.product_id'); + $minimalPriceExpression = 'LEAST(minimal_price, IFNULL(catalog_rule_price, minimal_price))'; + } + $orderByValue = new \Zend_Db_Expr( + '(' . + $minimalPriceExpression . + ' * selection.selection_qty' . + ')' + ); + } else { + $connection = $this->getConnection(); + $priceType = $connection->getIfNullSql( + 'price.selection_price_type', + 'selection.selection_price_type' + ); + $priceValue = $connection->getIfNullSql( + 'price.selection_price_value', + 'selection.selection_price_value' + ); + if (!$this->websiteScopePriceJoined) { + $websiteId = $this->_storeManager->getStore()->getWebsiteId(); + $this->getSelect()->joinLeft( + ['price' => $this->getTable('catalog_product_bundle_selection_price')], + 'selection.selection_id = price.selection_id AND price.website_id = ' . (int)$websiteId, + [] + ); + } + $price = $connection->getCheckSql( + $priceType . ' = 1', + (float) $product->getPrice() . ' * '. $priceValue . ' / 100', + $priceValue + ); + $orderByValue = new \Zend_Db_Expr('('. $price. ' * '. 'selection.selection_qty)'); + } + + $this->getSelect()->reset(Select::ORDER); + $this->getSelect()->order($orderByValue . ($searchMin ? Select::SQL_ASC : Select::SQL_DESC)); + $this->getSelect()->limit(1); + return $this; + } + + /** + * @return \Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor + * @deprecated + */ + private function getCatalogRuleProcessor() + { + if (null === $this->catalogRuleProcessor) { + $this->catalogRuleProcessor = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor::class); + } + + return $this->catalogRuleProcessor; + } } diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Selection/Plugin/Collection.php b/app/code/Magento/Bundle/Model/ResourceModel/Selection/Plugin/Collection.php index 12580eca2779d..296a694c5d00b 100644 --- a/app/code/Magento/Bundle/Model/ResourceModel/Selection/Plugin/Collection.php +++ b/app/code/Magento/Bundle/Model/ResourceModel/Selection/Plugin/Collection.php @@ -1,6 +1,6 @@ serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + parent::__construct( + $context, + $registry, + $taxData, + $filesystem, + $filterManager, + $resource, + $resourceCollection, + $data + ); + } + /** * Getting all available children for Invoice, Shipment or CreditMemo item * @@ -157,7 +205,7 @@ public function getSelectionAttributes($item) $options = $item->getOrderItem()->getProductOptions(); } if (isset($options['bundle_selection_attributes'])) { - return unserialize($options['bundle_selection_attributes']); + return $this->serializer->unserialize($options['bundle_selection_attributes']); } return null; } diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php index 2ac6e484bb5b5..d30281d014cbb 100644 --- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php +++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Creditmemo.php @@ -1,12 +1,15 @@ string = $string; parent::__construct( @@ -48,7 +56,8 @@ public function __construct( $filterManager, $resource, $resourceCollection, - $data + $data, + $serializer ); } diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php index 9b5d0b4a9c018..27bb34ffa4592 100644 --- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php +++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php @@ -1,15 +1,17 @@ string = $coreString; parent::__construct( @@ -49,7 +56,8 @@ public function __construct( $filterManager, $resource, $resourceCollection, - $data + $data, + $serializer ); } diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php index fec75878c3053..7bcc9ffb767b7 100644 --- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php +++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Shipment.php @@ -1,12 +1,15 @@ string = $string; parent::__construct( @@ -46,7 +54,8 @@ public function __construct( $filterManager, $resource, $resourceCollection, - $data + $data, + $serializer ); } diff --git a/app/code/Magento/Bundle/Model/Selection.php b/app/code/Magento/Bundle/Model/Selection.php index 9d0ee616fc60f..0c79190aed8ea 100644 --- a/app/code/Magento/Bundle/Model/Selection.php +++ b/app/code/Magento/Bundle/Model/Selection.php @@ -1,6 +1,6 @@ calculator = $calculator; $this->amountFactory = $amountFactory; $this->selectionFactory = $bundleSelectionFactory; $this->taxHelper = $taxHelper; $this->priceCurrency = $priceCurrency; + $this->selectionPriceListProvider = $selectionPriceListProvider; } /** @@ -143,12 +155,17 @@ public function getOptionsAmount( $baseAmount = 0., $useRegularPrice = false ) { - return $this->calculateBundleAmount( - $baseAmount, - $saleableItem, - $this->getSelectionAmounts($saleableItem, $searchMin, $useRegularPrice), - $exclude - ); + $cacheKey = implode('-', [$saleableItem->getId(), $exclude, $searchMin, $baseAmount, $useRegularPrice]); + if (!isset($this->optionAmount[$cacheKey])) { + $this->optionAmount[$cacheKey] = $this->calculateBundleAmount( + $baseAmount, + $saleableItem, + $this->getSelectionAmounts($saleableItem, $searchMin, $useRegularPrice), + $exclude + ); + } + + return $this->optionAmount[$cacheKey]; } /** @@ -174,42 +191,24 @@ public function getAmountWithoutOption($amount, Product $saleableItem) * @param bool $searchMin * @param bool $useRegularPrice * @return array - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function getSelectionAmounts(Product $bundleProduct, $searchMin, $useRegularPrice = false) { - // Flag shows - is it necessary to find minimal option amount in case if all options are not required - $shouldFindMinOption = false; - if ($searchMin - && $bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC - && !$this->hasRequiredOption($bundleProduct) - ) { - $shouldFindMinOption = true; - } - $canSkipRequiredOptions = $searchMin && !$shouldFindMinOption; + return $this->getSelectionPriceListProvider()->getPriceList($bundleProduct, $searchMin, $useRegularPrice); + } - $currentPrice = false; - $priceList = []; - foreach ($this->getBundleOptions($bundleProduct) as $option) { - if ($this->canSkipOption($option, $canSkipRequiredOptions)) { - continue; - } - $selectionPriceList = $this->createSelectionPriceList($option, $bundleProduct, $useRegularPrice); - $selectionPriceList = $this->processOptions($option, $selectionPriceList, $searchMin); - - $lastSelectionPrice = end($selectionPriceList); - $lastValue = $lastSelectionPrice->getAmount()->getValue() * $lastSelectionPrice->getQuantity(); - if ($shouldFindMinOption - && (!$currentPrice || - $lastValue < ($currentPrice->getAmount()->getValue() * $currentPrice->getQuantity())) - ) { - $currentPrice = end($selectionPriceList); - } elseif (!$shouldFindMinOption) { - $priceList = array_merge($priceList, $selectionPriceList); - } + /** + * @return SelectionPriceListProviderInterface + * @deprecated + */ + private function getSelectionPriceListProvider() + { + if (null === $this->selectionPriceListProvider) { + $this->selectionPriceListProvider = \Magento\Framework\App\ObjectManager::getInstance() + ->get(SelectionPriceListProviderInterface::class); } - return $shouldFindMinOption ? [$currentPrice] : $priceList; + + return $this->selectionPriceListProvider; } /** @@ -218,6 +217,7 @@ protected function getSelectionAmounts(Product $bundleProduct, $searchMin, $useR * @param \Magento\Bundle\Model\Option $option * @param bool $canSkipRequiredOption * @return bool + * @deprecated */ protected function canSkipOption($option, $canSkipRequiredOption) { @@ -229,6 +229,7 @@ protected function canSkipOption($option, $canSkipRequiredOption) * * @param Product $bundleProduct * @return bool + * @deprecated */ protected function hasRequiredOption($bundleProduct) { @@ -246,11 +247,14 @@ function ($item) { * * @param Product $saleableItem * @return \Magento\Bundle\Model\ResourceModel\Option\Collection + * @deprecated */ protected function getBundleOptions(Product $saleableItem) { - /** @var BundleOptionPrice $bundlePrice */ - $bundlePrice = $saleableItem->getPriceInfo()->getPrice(BundleOptionPrice::PRICE_CODE); + /** @var \Magento\Bundle\Pricing\Price\BundleOptionPrice $bundlePrice */ + $bundlePrice = $saleableItem->getPriceInfo()->getPrice( + \Magento\Bundle\Pricing\Price\BundleOptionPrice::PRICE_CODE + ); return $bundlePrice->getOptions(); } diff --git a/app/code/Magento/Bundle/Pricing/Adjustment/DefaultSelectionPriceListProvider.php b/app/code/Magento/Bundle/Pricing/Adjustment/DefaultSelectionPriceListProvider.php new file mode 100644 index 0000000000000..10f501164e32a --- /dev/null +++ b/app/code/Magento/Bundle/Pricing/Adjustment/DefaultSelectionPriceListProvider.php @@ -0,0 +1,208 @@ +selectionFactory = $bundleSelectionFactory; + } + + /** + * {@inheritdoc} + */ + public function getPriceList(Product $bundleProduct, $searchMin, $useRegularPrice) + { + $shouldFindMinOption = $this->isShouldFindMinOption($bundleProduct, $searchMin); + $canSkipRequiredOptions = $searchMin && !$shouldFindMinOption; + + /** @var \Magento\Bundle\Model\Product\Type $typeInstance */ + $typeInstance = $bundleProduct->getTypeInstance(); + $this->priceList = []; + + foreach ($this->getBundleOptions($bundleProduct) as $option) { + /** @var Option $option */ + if ($this->canSkipOption($option, $canSkipRequiredOptions)) { + continue; + } + + $selectionsCollection = $typeInstance->getSelectionsCollection( + [(int)$option->getOptionId()], + $bundleProduct + ); + $selectionsCollection->removeAttributeToSelect(); + $selectionsCollection->addQuantityFilter(); + + if (!$useRegularPrice) { + $selectionsCollection->addAttributeToSelect('special_price'); + $selectionsCollection->addAttributeToSelect('special_price_from'); + $selectionsCollection->addAttributeToSelect('special_price_to'); + $selectionsCollection->addAttributeToSelect('tax_class_id'); + } + + if (!$searchMin && $option->isMultiSelection()) { + $this->addMaximumMultiSelectionPriceList($bundleProduct, $selectionsCollection, $useRegularPrice); + } else { + $this->addMiniMaxPriceList($bundleProduct, $selectionsCollection, $searchMin, $useRegularPrice); + } + } + + if ($shouldFindMinOption) { + $this->processMinPriceForNonRequiredOptions(); + } + + return $this->priceList; + } + + /** + * Flag shows - is it necessary to find minimal option amount in case if all options are not required + * + * @param Product $bundleProduct + * @param bool $searchMin + * @return bool + */ + private function isShouldFindMinOption(Product $bundleProduct, $searchMin) + { + $shouldFindMinOption = false; + if ($searchMin + && $bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC + && !$this->hasRequiredOption($bundleProduct) + ) { + $shouldFindMinOption = true; + } + + return $shouldFindMinOption; + } + + /** + * Add minimum or maximum price for option + * + * @param Product $bundleProduct + * @param \Magento\Bundle\Model\ResourceModel\Selection\Collection $selectionsCollection + * @param bool $searchMin + * @param bool $useRegularPrice + * @return void + */ + private function addMiniMaxPriceList(Product $bundleProduct, $selectionsCollection, $searchMin, $useRegularPrice) + { + $selectionsCollection->addPriceFilter($bundleProduct, $searchMin, $useRegularPrice); + $selectionsCollection->setPage(0, 1); + + $selection = $selectionsCollection->getFirstItem(); + + if (!$selection->isEmpty()) { + $this->priceList[] = $this->selectionFactory->create( + $bundleProduct, + $selection, + $selection->getSelectionQty(), + [ + 'useRegularPrice' => $useRegularPrice, + ] + ); + } + } + + /** + * Add maximum price for multi selection option + * + * @param Product $bundleProduct + * @param \Magento\Bundle\Model\ResourceModel\Selection\Collection $selectionsCollection + * @param bool $useRegularPrice + * @return void + */ + private function addMaximumMultiSelectionPriceList(Product $bundleProduct, $selectionsCollection, $useRegularPrice) + { + $selectionsCollection->addPriceData(); + + foreach ($selectionsCollection as $selection) { + $this->priceList[] = $this->selectionFactory->create( + $bundleProduct, + $selection, + $selection->getSelectionQty(), + [ + 'useRegularPrice' => $useRegularPrice, + ] + ); + } + } + + /** + * @return void + */ + private function processMinPriceForNonRequiredOptions() + { + $minPrice = null; + $priceSelection = null; + foreach ($this->priceList as $price) { + $minPriceTmp = $price->getAmount()->getValue() * $price->getQuantity(); + if (!$minPrice || $minPriceTmp < $minPrice) { + $minPrice = $minPriceTmp; + $priceSelection = $price; + } + } + $this->priceList = $priceSelection ? [$priceSelection] : []; + } + + /** + * Check this option if it should be skipped + * + * @param Option $option + * @param bool $canSkipRequiredOption + * @return bool + */ + private function canSkipOption($option, $canSkipRequiredOption) + { + return $canSkipRequiredOption && !$option->getRequired(); + } + + /** + * Check the bundle product for availability of required options + * + * @param Product $bundleProduct + * @return bool + */ + private function hasRequiredOption($bundleProduct) + { + $collection = clone $this->getBundleOptions($bundleProduct); + $collection->clear(); + + return $collection->addFilter(Option::KEY_REQUIRED, 1)->getSize() > 0; + } + + /** + * Get bundle options + * + * @param Product $saleableItem + * @return \Magento\Bundle\Model\ResourceModel\Option\Collection + */ + private function getBundleOptions(Product $saleableItem) + { + return $saleableItem->getTypeInstance()->getOptionsCollection($saleableItem); + } +} diff --git a/app/code/Magento/Bundle/Pricing/Adjustment/SelectionPriceListProviderInterface.php b/app/code/Magento/Bundle/Pricing/Adjustment/SelectionPriceListProviderInterface.php new file mode 100644 index 0000000000000..13e10ca62f472 --- /dev/null +++ b/app/code/Magento/Bundle/Pricing/Adjustment/SelectionPriceListProviderInterface.php @@ -0,0 +1,23 @@ +objectManager->create(self::SELECTION_CLASS_DEFAULT, $arguments); - if (!$selectionPrice instanceof BundleSelectionPrice) { - throw new \InvalidArgumentException( - get_class($selectionPrice) . ' doesn\'t extend BundleSelectionPrice' - ); - } - return $selectionPrice; + + return $this->objectManager->create(self::SELECTION_CLASS_DEFAULT, $arguments); } } diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php index 5222e52c1145d..97230a76ba160 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php @@ -1,6 +1,6 @@ value) { return $this->value; } + $product = $this->selection; + $bundleSelectionKey = 'bundle-selection-value-' . $product->getSelectionId(); + if ($product->hasData($bundleSelectionKey)) { + return $product->getData($bundleSelectionKey); + } $priceCode = $this->useRegularPrice ? BundleRegularPrice::PRICE_CODE : FinalPrice::PRICE_CODE; if ($this->bundleProduct->getPriceType() == Price::PRICE_TYPE_DYNAMIC) { @@ -131,7 +136,7 @@ public function getValue() $value = $this->discountCalculator->calculateDiscount($this->bundleProduct, $value); } $this->value = $this->priceCurrency->round($value); - + $product->setData($bundleSelectionKey, $this->value); return $this->value; } @@ -142,18 +147,25 @@ public function getValue() */ public function getAmount() { - if (!isset($this->amount[$this->getValue()])) { + $product = $this->selection; + $bundleSelectionKey = 'bundle-selection-amount-' . $product->getSelectionId(); + if ($product->hasData($bundleSelectionKey)) { + return $product->getData($bundleSelectionKey); + } + $value = $this->getValue(); + if (!isset($this->amount[$value])) { $exclude = null; if ($this->getProduct()->getTypeId() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) { $exclude = $this->excludeAdjustment; } - $this->amount[$this->getValue()] = $this->calculator->getAmount( - $this->getValue(), + $this->amount[$value] = $this->calculator->getAmount( + $value, $this->getProduct(), $exclude ); + $product->setData($bundleSelectionKey, $this->amount[$value]); } - return $this->amount[$this->getValue()]; + return $this->amount[$value]; } /** diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php index e6c0f90e24a5c..611f981272bd3 100644 --- a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php @@ -1,6 +1,6 @@ item = $item; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency); } @@ -74,13 +85,16 @@ public function getOptions() // get bundle options $optionsQuoteItemOption = $this->item->getOptionByCode('bundle_option_ids'); - $bundleOptionsIds = $optionsQuoteItemOption ? unserialize($optionsQuoteItemOption->getValue()) : []; + $bundleOptionsIds = $optionsQuoteItemOption + ? $this->serializer->unserialize($optionsQuoteItemOption->getValue()) + : []; + if ($bundleOptionsIds) { /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */ $optionsCollection = $typeInstance->getOptionsByIds($bundleOptionsIds, $bundleProduct); // get and add bundle selections collection $selectionsQuoteItemOption = $this->item->getOptionByCode('bundle_selection_ids'); - $bundleSelectionIds = unserialize($selectionsQuoteItemOption->getValue()); + $bundleSelectionIds = $this->serializer->unserialize($selectionsQuoteItemOption->getValue()); if ($bundleSelectionIds) { $selectionsCollection = $typeInstance->getSelectionsByIds($bundleSelectionIds, $bundleProduct); $bundleOptions = $optionsCollection->appendSelections($selectionsCollection, true); diff --git a/app/code/Magento/Bundle/Pricing/Price/DiscountCalculator.php b/app/code/Magento/Bundle/Pricing/Price/DiscountCalculator.php index 0f8506cf2b18e..032e436239c14 100644 --- a/app/code/Magento/Bundle/Pricing/Price/DiscountCalculator.php +++ b/app/code/Magento/Bundle/Pricing/Price/DiscountCalculator.php @@ -1,6 +1,6 @@ percent === null) { - $percent = parent::getValue(); - $this->percent = ($percent) ? max(0, min(100, 100 - $percent)) : null; + $prices = $this->getStoredTierPrices(); + $prevQty = PriceInfoInterface::PRODUCT_QUANTITY_DEFAULT; + $this->value = $prevPrice = false; + $priceGroup = $this->groupManagement->getAllCustomersGroup()->getId(); + + foreach ($prices as $price) { + if (!$this->canApplyTierPrice($price, $priceGroup, $prevQty) + || !isset($price['percentage_value']) + || !is_numeric($price['percentage_value']) + ) { + continue; + } + if (false === $prevPrice || $this->isFirstPriceBetter($price['website_price'], $prevPrice)) { + $prevPrice = $price['website_price']; + $prevQty = $price['price_qty']; + $priceGroup = $price['cust_group']; + $this->percent = max(0, min(100, 100 - $price['percentage_value'])); + } + } } return $this->percent; } @@ -90,13 +108,4 @@ public function isPercentageDiscount() { return true; } - - /** - * @param AmountInterface $amount - * @return float - */ - public function getSavePercent(AmountInterface $amount) - { - return round($amount->getBaseAmount()); - } } diff --git a/app/code/Magento/Bundle/Pricing/Render/FinalPriceBox.php b/app/code/Magento/Bundle/Pricing/Render/FinalPriceBox.php index 23089108d8bf7..0a80dc3ede123 100644 --- a/app/code/Magento/Bundle/Pricing/Render/FinalPriceBox.php +++ b/app/code/Magento/Bundle/Pricing/Render/FinalPriceBox.php @@ -1,6 +1,6 @@ startSetup(); - + $customerGroupTable = $setup->getConnection()->describeTable($setup->getTable('customer_group')); + $customerGroupIdType = $customerGroupTable['customer_group_id']['DATA_TYPE'] == 'int' + ? \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER : $customerGroupTable['customer_group_id']['DATA_TYPE']; /** * Create table 'catalog_product_bundle_option' */ @@ -340,7 +342,7 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con ) ->addColumn( 'customer_group_id', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, + $customerGroupIdType, null, ['unsigned' => true, 'nullable' => false, 'primary' => true], 'Customer Group Id' diff --git a/app/code/Magento/Bundle/Setup/Recurring.php b/app/code/Magento/Bundle/Setup/Recurring.php index fa585446a98c0..1eb5fd6c80627 100644 --- a/app/code/Magento/Bundle/Setup/Recurring.php +++ b/app/code/Magento/Bundle/Setup/Recurring.php @@ -1,6 +1,6 @@ getVersion(), '2.0.3', '<')) { + $tables = [ + 'catalog_product_index_price_bundle_idx', + 'catalog_product_index_price_bundle_opt_idx', + 'catalog_product_index_price_bundle_opt_tmp', + 'catalog_product_index_price_bundle_sel_idx', + 'catalog_product_index_price_bundle_sel_tmp', + 'catalog_product_index_price_bundle_tmp', + ]; + foreach ($tables as $table) { + $setup->getConnection()->modifyColumn( + $setup->getTable($table), + 'customer_group_id', + ['type' => 'integer', 'nullable' => false] + ); + } + } + $setup->endSetup(); } } diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/CheckboxTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/CheckboxTest.php index e8c5fa7899ffc..c2b7895772347 100644 --- a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/CheckboxTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/CheckboxTest.php @@ -1,6 +1,6 @@ orderItem = $this->getMock( @@ -22,9 +25,12 @@ protected function setUp() '', false ); - + $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->model = $objectManager->getObject(\Magento\Bundle\Block\Adminhtml\Sales\Order\Items\Renderer::class); + $this->model = $objectManager->getObject( + \Magento\Bundle\Block\Adminhtml\Sales\Order\Items\Renderer::class, + ['serializer' => $this->serializer] + ); } /** @@ -221,21 +227,25 @@ public function isChildCalculatedWithItemDataProvider() ]; } - /** - * @dataProvider getSelectionAttributesDataProvider - */ - public function testGetSelectionAttributes($productOptions, $result) + public function testGetSelectionAttributes() { - $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions)); - $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem)); + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([])); + $this->assertNull($this->model->getSelectionAttributes($this->orderItem)); } - public function getSelectionAttributesDataProvider() + public function testGetSelectionAttributesWithBundle() { - return [ - [[], null], - [['bundle_selection_attributes' => 'a:1:{i:0;i:1;}'], [0 => 1]], - ]; + $bundleAttributes = 'Serialized value'; + $options = ['bundle_selection_attributes' => $bundleAttributes]; + $unserializedResult = 'result of "bundle_selection_attributes" unserialization'; + + $this->serializer->expects($this->any()) + ->method('unserialize') + ->with($bundleAttributes) + ->will($this->returnValue($unserializedResult)); + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options)); + + $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem)); } public function testGetOrderOptions() diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php index 72c4a40fbbb54..94647c6a49577 100644 --- a/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Block/Adminhtml/Sales/Order/View/Items/RendererTest.php @@ -1,6 +1,6 @@ orderItem = $this->getMock( @@ -22,10 +25,11 @@ protected function setUp() '', false ); - + $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $objectManager->getObject( - \Magento\Bundle\Block\Adminhtml\Sales\Order\View\Items\Renderer::class + \Magento\Bundle\Block\Adminhtml\Sales\Order\View\Items\Renderer::class, + ['serializer' => $this->serializer] ); } @@ -141,13 +145,25 @@ public function isChildCalculatedWithItemDataProvider() ]; } - /** - * @dataProvider getSelectionAttributesDataProvider - */ - public function testGetSelectionAttributes($productOptions, $result) + public function testGetSelectionAttributes() { - $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions)); - $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem)); + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([])); + $this->assertNull($this->model->getSelectionAttributes($this->orderItem)); + } + + public function testGetSelectionAttributesWithBundle() + { + $bundleAttributes = 'Serialized value'; + $options = ['bundle_selection_attributes' => $bundleAttributes]; + $unserializedResult = 'result of "bundle_selection_attributes" unserialization'; + + $this->serializer->expects($this->any()) + ->method('unserialize') + ->with($bundleAttributes) + ->will($this->returnValue($unserializedResult)); + + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options)); + $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem)); } public function getSelectionAttributesDataProvider() diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/Bundle/OptionTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/Bundle/OptionTest.php index 4e4d50a443b64..39eb1d9188436 100644 --- a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/Bundle/OptionTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/Bundle/OptionTest.php @@ -1,6 +1,6 @@ bundleProductPriceFactory = $this->getMockBuilder(\Magento\Bundle\Model\Product\PriceFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $this->_bundleBlock = $objectHelper->getObject( - \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class, - [ - 'productPrice' => $this->bundleProductPriceFactory - ] - ); + $this->product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) ->disableOriginalConstructor() ->setMethods( @@ -57,45 +63,87 @@ protected function setUp() 'getPreconfiguredValues' ] )->getMock(); + $registry = $this->getMockBuilder(\Magento\Framework\Registry::class) + ->disableOriginalConstructor() + ->setMethods(['registry']) + ->getMock(); + $registry->expects($this->any()) + ->method('registry') + ->willReturn($this->product); + $this->eventManager = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->jsonEncoder = $this->getMockBuilder(\Magento\Framework\Json\Encoder::class) + ->disableOriginalConstructor() + ->getMock(); + $this->catalogProduct = $this->getMockBuilder(\Magento\Catalog\Helper\Product::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var $bundleBlock BundleBlock */ + $this->bundleBlock = $objectHelper->getObject( + \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class, + [ + 'registry' => $registry, + 'eventManager' => $this->eventManager, + 'jsonEncoder' => $this->jsonEncoder, + 'productPrice' => $this->bundleProductPriceFactory, + 'catalogProduct' => $this->catalogProduct + ] + ); + + $ruleProcessor = $this->getMockBuilder( + \Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor::class + )->disableOriginalConstructor()->getMock(); + $objectHelper->setBackwardCompatibleProperty( + $this->bundleBlock, + 'catalogRuleProcessor', + $ruleProcessor + ); } public function testGetOptionHtmlNoRenderer() { - $option = $this->getMock(\Magento\Bundle\Model\Option::class, ['getType', '__wakeup'], [], '', false); - $option->expects($this->exactly(2))->method('getType')->will($this->returnValue('checkbox')); + $option = $this->getMockBuilder(\Magento\Bundle\Model\Option::class) + ->setMethods(['getType']) + ->disableOriginalConstructor() + ->getMock(); + $option->expects($this->any())->method('getType')->willReturn('checkbox'); + + $layout = $this->getMockBuilder(\Magento\Framework\View\Layout::class) + ->setMethods(['getChildName', 'getBlock']) + ->disableOriginalConstructor() + ->getMock(); + $layout->expects($this->any())->method('getChildName')->willReturn(false); + $this->bundleBlock->setLayout($layout); $this->assertEquals( 'There is no defined renderer for "checkbox" option type.', - $this->_bundleBlock->getOptionHtml($option) + $this->bundleBlock->getOptionHtml($option) ); } public function testGetOptionHtml() { - $option = $this->getMock(\Magento\Bundle\Model\Option::class, ['getType', '__wakeup'], [], '', false); - $option->expects($this->exactly(1))->method('getType')->will($this->returnValue('checkbox')); - - $optionBlock = $this->getMock( - \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox::class, - ['setOption', 'toHtml'], - [], - '', - false - ); - $optionBlock->expects($this->any())->method('setOption')->will($this->returnValue($optionBlock)); - $optionBlock->expects($this->any())->method('toHtml')->will($this->returnValue('option html')); - $layout = $this->getMock( - \Magento\Framework\View\Layout::class, - ['getChildName', 'getBlock'], - [], - '', - false - ); - $layout->expects($this->any())->method('getChildName')->will($this->returnValue('name')); - $layout->expects($this->any())->method('getBlock')->will($this->returnValue($optionBlock)); - $this->_bundleBlock->setLayout($layout); + $option = $this->getMockBuilder(\Magento\Bundle\Model\Option::class) + ->setMethods(['getType']) + ->disableOriginalConstructor() + ->getMock(); + $option->expects($this->once())->method('getType')->willReturn('checkbox'); + + $optionBlock = $this->getMockBuilder( + \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox::class + )->setMethods(['setOption', 'toHtml'])->disableOriginalConstructor()->getMock(); + $optionBlock->expects($this->any())->method('setOption')->willReturnSelf(); + $optionBlock->expects($this->any())->method('toHtml')->willReturn('option html'); + $layout = $this->getMockBuilder(\Magento\Framework\View\Layout::class) + ->setMethods(['getChildName', 'getBlock']) + ->disableOriginalConstructor() + ->getMock(); + $layout->expects($this->any())->method('getChildName')->willReturn('name'); + $layout->expects($this->any())->method('getBlock')->willReturn($optionBlock); + $this->bundleBlock->setLayout($layout); - $this->assertEquals('option html', $this->_bundleBlock->getOptionHtml($option)); + $this->assertEquals('option html', $this->bundleBlock->getOptionHtml($option)); } public function testGetJsonConfigFixedPriceBundleNoOption() @@ -103,7 +151,7 @@ public function testGetJsonConfigFixedPriceBundleNoOption() $options = []; $finalPriceMock = $this->getPriceMock( [ - 'getPriceWithoutOption' => new MagentoObject( + 'getPriceWithoutOption' => new \Magento\Framework\DataObject( [ 'value' => 100, 'base_amount' => 100, @@ -113,7 +161,7 @@ public function testGetJsonConfigFixedPriceBundleNoOption() ); $regularPriceMock = $this->getPriceMock( [ - 'getAmount' => new MagentoObject( + 'getAmount' => new \Magento\Framework\DataObject( [ 'value' => 110, 'base_amount' => 110, @@ -127,12 +175,12 @@ public function testGetJsonConfigFixedPriceBundleNoOption() ]; $priceInfo = $this->getPriceInfoMock($prices); - $this->_bundleBlock = $this->setupBundleBlock( + $this->updateBundleBlock( $options, $priceInfo, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED ); - $jsonConfig = $this->_bundleBlock->getJsonConfig(); + $jsonConfig = $this->bundleBlock->getJsonConfig(); $this->assertEquals(110, $jsonConfig['prices']['oldPrice']['amount']); $this->assertEquals(100, $jsonConfig['prices']['basePrice']['amount']); $this->assertEquals(100, $jsonConfig['prices']['finalPrice']['amount']); @@ -148,7 +196,9 @@ public function testGetJsonConfigFixedPriceBundle() 'Selection 1', 23, [ - ['price' => new MagentoObject(['base_amount' => $baseAmount, 'value' => $basePriceValue])] + ['price' => new \Magento\Framework\DataObject( + ['base_amount' => $baseAmount, 'value' => $basePriceValue] + )] ], true, true @@ -162,21 +212,21 @@ public function testGetJsonConfigFixedPriceBundle() $bundleProductPrice->expects($this->at(0)) ->method('getLowestPrice') ->with($this->product, $baseAmount) - ->will($this->returnValue(999)); + ->willReturn(999); $bundleProductPrice->expects($this->at(1)) ->method('getLowestPrice') ->with($this->product, $basePriceValue) - ->will($this->returnValue(888)); + ->willReturn(888); $this->bundleProductPriceFactory->expects($this->once()) ->method('create') - ->will($this->returnValue($bundleProductPrice)); + ->willReturn($bundleProductPrice); $options = [ $this->createOption(1, 'Title `1', $selections), ]; $finalPriceMock = $this->getPriceMock( [ - 'getPriceWithoutOption' => new MagentoObject( + 'getPriceWithoutOption' => new \Magento\Framework\DataObject( [ 'value' => 100, 'base_amount' => 100, @@ -186,7 +236,7 @@ public function testGetJsonConfigFixedPriceBundle() ); $regularPriceMock = $this->getPriceMock( [ - 'getAmount' => new MagentoObject( + 'getAmount' => new \Magento\Framework\DataObject( [ 'value' => 110, 'base_amount' => 110, @@ -207,7 +257,7 @@ public function testGetJsonConfigFixedPriceBundle() $this->product->expects($this->once()) ->method('hasPreconfiguredValues') - ->will($this->returnValue(true)); + ->willReturn(true); $preconfiguredValues = new \Magento\Framework\DataObject( [ 'bundle_option' => [ @@ -217,14 +267,14 @@ public function testGetJsonConfigFixedPriceBundle() ); $this->product->expects($this->once()) ->method('getPreconfiguredValues') - ->will($this->returnValue($preconfiguredValues)); + ->willReturn($preconfiguredValues); - $this->_bundleBlock = $this->setupBundleBlock( + $this->updateBundleBlock( $options, $priceInfo, \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED ); - $jsonConfig = $this->_bundleBlock->getJsonConfig(); + $jsonConfig = $this->bundleBlock->getJsonConfig(); $this->assertEquals(110, $jsonConfig['prices']['oldPrice']['amount']); $this->assertEquals(100, $jsonConfig['prices']['basePrice']['amount']); $this->assertEquals(100, $jsonConfig['prices']['finalPrice']['amount']); @@ -234,88 +284,48 @@ public function testGetJsonConfigFixedPriceBundle() * @param array $options * @param \Magento\Framework\Pricing\PriceInfo\Base|\PHPUnit_Framework_MockObject_MockObject $priceInfo * @param string $priceType - * @return BundleBlock + * @return void */ - private function setupBundleBlock($options, $priceInfo, $priceType) + private function updateBundleBlock($options, $priceInfo, $priceType) { - $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - - - $eventManager = $this->getMockBuilder(\Magento\Framework\Event\Manager::class) - ->disableOriginalConstructor() - ->getMock(); - $eventManager->expects($this->any())->method('dispatch')->will($this->returnValue(true)); - + $this->eventManager->expects($this->any())->method('dispatch')->willReturn(true); $optionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Option\Collection::class) ->disableOriginalConstructor() ->getMock(); $optionCollection->expects($this->any()) ->method('appendSelections') - ->will($this->returnValue($options)); + ->willReturn($options); + + $selectionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $selectionCollection->expects($this->once())->method('addTierPriceData'); $typeInstance = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type::class) ->disableOriginalConstructor() ->getMock(); $typeInstance->expects($this->any()) ->method('getOptionsCollection') - ->will($this->returnValue($optionCollection)); + ->willReturn($optionCollection); $typeInstance->expects($this->any()) ->method('getStoreFilter') - ->will($this->returnValue(true)); + ->willReturn(true); + $typeInstance->expects($this->once()) + ->method('getSelectionsCollection') + ->willReturn($selectionCollection); $this->product->expects($this->any()) ->method('getTypeInstance') - ->will($this->returnValue($typeInstance)); + ->willReturn($typeInstance); $this->product->expects($this->any()) ->method('getPriceInfo') - ->will($this->returnValue($priceInfo)); + ->willReturn($priceInfo); $this->product->expects($this->any()) ->method('getPriceType') - ->will($this->returnValue($priceType)); - - $registry = $this->getMockBuilder(\Magento\Framework\Registry::class) - ->disableOriginalConstructor() - ->setMethods(['registry']) - ->getMock(); - $registry->expects($this->once()) - ->method('registry') - ->will($this->returnValue($this->product)); - - $taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) - ->disableOriginalConstructor() - ->getMock(); - - $context = $this->getMockBuilder(\Magento\Catalog\Block\Product\Context::class) - ->disableOriginalConstructor() - ->getMock(); - $context->expects($this->any()) - ->method('getRegistry') - ->will($this->returnValue($registry)); - $context->expects($this->any()) - ->method('getTaxData') - ->will($this->returnValue($taxHelperMock)); - $context->expects($this->any()) - ->method('getEventManager') - ->will($this->returnValue($eventManager)); - - $jsonEncoderMock = $this->getMockBuilder(\Magento\Framework\Json\Encoder::class) - ->disableOriginalConstructor() - ->getMock(); - $jsonEncoderMock->expects($this->any()) + ->willReturn($priceType); + $this->jsonEncoder->expects($this->any()) ->method('encode') ->will($this->returnArgument(0)); - - /** @var $bundleBlock BundleBlock */ - $bundleBlock = $objectHelper->getObject( - \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class, - [ - 'context' => $context, - 'jsonEncoder' => $jsonEncoderMock, - 'productPrice' => $this->bundleProductPriceFactory - ] - ); - - return $bundleBlock; } private function getPriceInfoMock($price) @@ -331,13 +341,13 @@ private function getPriceInfoMock($price) $priceInfoMock->expects($this->at($counter)) ->method('getPrice') ->with($priceType) - ->will($this->returnValue($priceValue)); + ->willReturn($priceValue); $counter++; } } else { $priceInfoMock->expects($this->any()) ->method('getPrice') - ->will($this->returnValue($price)); + ->willReturn($price); } return $priceInfoMock; } @@ -355,7 +365,7 @@ private function getPriceMock($prices) foreach ($prices as $methodName => $amount) { $priceMock->expects($this->any()) ->method($methodName) - ->will($this->returnValue($amount)); + ->willReturn($amount); } return $priceMock; @@ -373,15 +383,15 @@ private function getAmountPriceMock($value, $baseAmount, array $selectionAmounts ->disableOriginalConstructor() ->setMethods(['getValue', 'getBaseAmount', 'getOptionSelectionAmount']) ->getMockForAbstractClass(); - $amountPrice->expects($this->any())->method('getValue')->will($this->returnValue($value)); - $amountPrice->expects($this->any())->method('getBaseAmount')->will($this->returnValue($baseAmount)); + $amountPrice->expects($this->any())->method('getValue')->willReturn($value); + $amountPrice->expects($this->any())->method('getBaseAmount')->willReturn($baseAmount); foreach ($selectionAmounts as $selectionAmount) { $amountPrice->expects($this->any()) ->method('getOptionSelectionAmount') ->with($selectionAmount['item']) ->will( $this->returnValue( - new MagentoObject( + new \Magento\Framework\DataObject( [ 'value' => $selectionAmount['value'], 'base_amount' => $selectionAmount['base_amount'], @@ -414,7 +424,6 @@ private function createOption( ->disableOriginalConstructor() ->setMethods( [ - '__wakeup', 'getId', 'getTitle', 'getSelections', @@ -423,12 +432,12 @@ private function createOption( 'getIsDefault', ] ) - ->getMock(); - $option->expects($this->any())->method('getId')->will($this->returnValue($id)); - $option->expects($this->any())->method('getTitle')->will($this->returnValue($title)); - $option->expects($this->any())->method('getSelections')->will($this->returnValue($selections)); - $option->expects($this->any())->method('getType')->will($this->returnValue($type)); - $option->expects($this->any())->method('getRequired')->will($this->returnValue($isRequired)); + ->getMockForAbstractClass(); + $option->expects($this->any())->method('getId')->willReturn($id); + $option->expects($this->any())->method('getTitle')->willReturn($title); + $option->expects($this->any())->method('getSelections')->willReturn($selections); + $option->expects($this->any())->method('getType')->willReturn($type); + $option->expects($this->any())->method('getRequired')->willReturn($isRequired); return $option; } @@ -453,42 +462,72 @@ private function createOptionSelection( ) { $selection = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'getSelectionId', - 'getSelectionQty', - 'getPriceInfo', - 'getSelectionCanChangeQty', - 'getName', - 'getIsDefault', - 'isSalable', - ] - )->getMock(); + ->getMock(); $tierPrice = $this->getMockBuilder(\Magento\Bundle\Pricing\Price\TierPrice::class) ->disableOriginalConstructor() ->setMethods(['getTierPriceList']) ->getMock(); - $tierPrice->expects($this->any()) - ->method('getTierPriceList') - ->will($this->returnValue($tierPriceList)); + $tierPrice->expects($this->any())->method('getTierPriceList')->willReturn($tierPriceList); $priceInfo = $this->getMockBuilder(\Magento\Framework\Pricing\PriceInfo\Base::class) ->disableOriginalConstructor() ->setMethods(['getPrice']) ->getMock(); - $priceInfo->expects($this->any()) - ->method('getPrice') - ->will($this->returnValue($tierPrice)); - - $selection->expects($this->any())->method('getSelectionId')->will($this->returnValue($id)); - $selection->expects($this->any())->method('getName')->will($this->returnValue($name)); - $selection->expects($this->any())->method('getSelectionQty')->will($this->returnValue($qty)); - $selection->expects($this->any())->method('getPriceInfo')->will($this->returnValue($priceInfo)); - $selection->expects($this->any())->method('getSelectionCanChangeQty')->will( - $this->returnValue($isCanChangeQty) - ); - $selection->expects($this->any())->method('getIsDefault')->will($this->returnValue($isDefault)); - $selection->expects($this->any())->method('isSalable')->will($this->returnValue($isSalable)); + $priceInfo->expects($this->any())->method('getPrice')->willReturn($tierPrice); + $selection->expects($this->any())->method('getSelectionId')->willReturn($id); + $selection->expects($this->any())->method('getName')->willReturn($name); + $selection->expects($this->any())->method('getSelectionQty')->willReturn($qty); + $selection->expects($this->any())->method('getPriceInfo')->willReturn($priceInfo); + $selection->expects($this->any())->method('getSelectionCanChangeQty')->willReturn($isCanChangeQty); + $selection->expects($this->any())->method('getIsDefault')->willReturn($isDefault); + $selection->expects($this->any())->method('isSalable')->willReturn($isSalable); return $selection; } + + /** + * @dataProvider getOptionsDataProvider + * @param bool $stripSelection + */ + public function testGetOptions($stripSelection) + { + $newOptions = ['option_1', 'option_2']; + + $optionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Option\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $selectionConnection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $typeInstance = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type::class) + ->disableOriginalConstructor() + ->getMock(); + + $optionCollection->expects($this->any())->method('appendSelections') + ->with($selectionConnection, $stripSelection, true) + ->willReturn($newOptions); + $typeInstance->expects($this->any())->method('setStoreFilter')->with(0, $this->product) + ->willReturn($optionCollection); + $typeInstance->expects($this->any())->method('getStoreFilter')->willReturn(true); + $typeInstance->expects($this->any())->method('getOptionsCollection')->willReturn($optionCollection); + $typeInstance->expects($this->any())->method('getOptionsIds')->willReturn([1, 2]); + $typeInstance->expects($this->once())->method('getSelectionsCollection')->with([1, 2], $this->product) + ->willReturn($selectionConnection); + $this->product->expects($this->any()) + ->method('getTypeInstance')->willReturn($typeInstance); + $this->product->expects($this->any())->method('getStoreId') ->willReturn(0); + $this->catalogProduct->expects($this->once())->method('getSkipSaleableCheck')->willReturn(true); + + $this->assertEquals($newOptions, $this->bundleBlock->getOptions($stripSelection)); + } + + /** + * @return array + */ + public function getOptionsDataProvider() + { + return [ + [true], + [false] + ]; + } } diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php index d81908bd62506..c887339788ff1 100644 --- a/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Block/Sales/Order/Items/RendererTest.php @@ -1,6 +1,6 @@ orderItem = $this->getMock( @@ -23,8 +26,12 @@ protected function setUp() false ); + $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->model = $objectManager->getObject(\Magento\Bundle\Block\Sales\Order\Items\Renderer::class); + $this->model = $objectManager->getObject( + \Magento\Bundle\Block\Sales\Order\Items\Renderer::class, + ['serializer' => $this->serializer] + ); } /** @@ -221,21 +228,25 @@ public function isChildCalculatedWithItemDataProvider() ]; } - /** - * @dataProvider getSelectionAttributesDataProvider - */ - public function testGetSelectionAttributes($productOptions, $result) + public function testGetSelectionAttributes() { - $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions)); - $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem)); + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([])); + $this->assertNull($this->model->getSelectionAttributes($this->orderItem)); } - public function getSelectionAttributesDataProvider() + public function testGetSelectionAttributesWithBundle() { - return [ - [[], null], - [['bundle_selection_attributes' => 'a:1:{i:0;i:1;}'], [0 => 1]], - ]; + $bundleAttributes = 'Serialized value'; + $options = ['bundle_selection_attributes' => $bundleAttributes]; + $unserializedResult = 'result of "bundle_selection_attributes" unserialization'; + + $this->serializer->expects($this->any()) + ->method('unserialize') + ->with($bundleAttributes) + ->will($this->returnValue($unserializedResult)); + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options)); + + $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem)); } /** diff --git a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Product/Edit/FormTest.php b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Product/Edit/FormTest.php index 365cd26b9b9e2..bc67d862297c1 100644 --- a/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Product/Edit/FormTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Controller/Adminhtml/Bundle/Product/Edit/FormTest.php @@ -1,6 +1,6 @@ pricingHelper = $this->getMock( @@ -48,6 +53,16 @@ protected function setUp() \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface::class, ['getQty', 'getProduct', 'getOptionByCode', 'getFileDownloadParams'] ); + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->getMockForAbstractClass(); + + $this->serializer->expects($this->any()) + ->method('unserialize') + ->willReturnCallback( + function ($value) { + return json_decode($value, true); + } + ); $this->helper = (new ObjectManager($this))->getObject( \Magento\Bundle\Helper\Catalog\Product\Configuration::class, @@ -55,6 +70,7 @@ protected function setUp() 'pricingHelper' => $this->pricingHelper, 'productConfiguration' => $this->productConfiguration, 'escaper' => $this->escaper, + 'serializer' => $this->serializer ] ); } @@ -127,8 +143,7 @@ public function testGetBundleOptionsEmptyBundleOptionsIds() public function testGetBundleOptionsEmptyBundleSelectionIds() { - $optionIds = 'a:1:{i:0;i:1;}'; - + $optionIds = '{"0":"1"}'; $collection = $this->getMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class, [], [], '', false); $product = $this->getMock( \Magento\Catalog\Model\Product::class, @@ -152,7 +167,7 @@ public function testGetBundleOptionsEmptyBundleSelectionIds() $selectionOption->expects($this->once())->method('getValue')->will($this->returnValue('')); $itemOption->expects($this->once())->method('getValue')->will($this->returnValue($optionIds)); - $typeInstance->expects($this->once())->method('getOptionsByIds')->with(unserialize($optionIds), $product) + $typeInstance->expects($this->once())->method('getOptionsByIds')->with(json_decode($optionIds, true), $product) ->will($this->returnValue($collection)); $product->expects($this->once())->method('getTypeInstance')->will($this->returnValue($typeInstance)); $this->item->expects($this->once())->method('getProduct')->will($this->returnValue($product)); @@ -169,8 +184,8 @@ public function testGetBundleOptionsEmptyBundleSelectionIds() */ public function testGetOptions() { - $optionIds = 'a:1:{i:0;i:1;}'; - $selectionIds = 'a:1:{i:0;s:1:"2";}'; + $optionIds = '{"0":"1"}'; + $selectionIds = '{"0":"2"}'; $selectionId = '2'; $product = $this->getMock( \Magento\Catalog\Model\Product::class, @@ -237,9 +252,11 @@ public function testGetOptions() $collection->expects($this->once())->method('appendSelections')->with($collection2, true) ->will($this->returnValue([$bundleOption])); $itemOption->expects($this->once())->method('getValue')->will($this->returnValue($optionIds)); - $typeInstance->expects($this->once())->method('getOptionsByIds')->with(unserialize($optionIds), $product) + $typeInstance->expects($this->once())->method('getOptionsByIds')->with(json_decode($optionIds, true), $product) ->will($this->returnValue($collection)); - $typeInstance->expects($this->once())->method('getSelectionsByIds')->with(unserialize($selectionIds), $product) + $typeInstance->expects($this->once()) + ->method('getSelectionsByIds') + ->with(json_decode($selectionIds, true), $product) ->will($this->returnValue($collection2)); $product->expects($this->once())->method('getTypeInstance')->will($this->returnValue($typeInstance)); $product->expects($this->any())->method('getCustomOption')->with('selection_qty_' . $selectionId) diff --git a/app/code/Magento/Bundle/Test/Unit/Helper/DataTest.php b/app/code/Magento/Bundle/Test/Unit/Helper/DataTest.php index 93b6cbc6769ab..a532c578375c3 100644 --- a/app/code/Magento/Bundle/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Helper/DataTest.php @@ -1,6 +1,6 @@ ruleFactoryMock = $this->getMock( @@ -90,6 +104,16 @@ protected function setUp() false ); $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->getMock(); + $this->serializer->expects($this->any()) + ->method('unserialize') + ->willReturnCallback( + function ($value) { + return json_decode($value, true); + } + ); $objectManagerHelper = new ObjectManagerHelper($this); $this->model = $objectManagerHelper->getObject( @@ -104,12 +128,15 @@ protected function setUp() 'groupManagement' => $this->groupManagement, 'tierPriceFactory' => $tpFactory, 'config' => $scopeConfig, - 'catalogData' => $this->catalogHelperMock + 'catalogData' => $this->catalogHelperMock, + 'serializer' => $this->serializer ] ); } /** + * Test for calculateSpecialPrice(). + * * @param float $finalPrice * @param float $specialPrice * @param int $callsNumber @@ -119,6 +146,7 @@ protected function setUp() * @covers \Magento\Bundle\Model\Product\Price::calculateSpecialPrice * @covers \Magento\Bundle\Model\Product\Price::__construct * @dataProvider calculateSpecialPrice + * @return void */ public function testCalculateSpecialPrice($finalPrice, $specialPrice, $callsNumber, $dateInInterval, $expected) { @@ -138,6 +166,8 @@ public function testCalculateSpecialPrice($finalPrice, $specialPrice, $callsNumb } /** + * Data provider for calculateSpecialPrice() test. + * * @return array */ public function calculateSpecialPrice() @@ -152,6 +182,11 @@ public function calculateSpecialPrice() ]; } + /** + * Test for getTotalBundleItemsPrice() with noCustom options. + * + * @return void + */ public function testGetTotalBundleItemsPriceWithNoCustomOptions() { $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) @@ -166,8 +201,11 @@ public function testGetTotalBundleItemsPriceWithNoCustomOptions() } /** + * Test for getTotalBundleItemsPrice() with empty options. + * * @param string|null $value * @dataProvider dataProviderWithEmptyOptions + * @return void */ public function testGetTotalBundleItemsPriceWithEmptyOptions($value) { @@ -191,22 +229,28 @@ public function testGetTotalBundleItemsPriceWithEmptyOptions($value) $dataObjectMock->expects($this->once()) ->method('getValue') ->willReturn($value); - $this->assertEquals(0, $this->model->getTotalBundleItemsPrice($productMock)); } /** + * Data provider for getTotalBundleItemsPrice() with empty options. + * * @return array */ public function dataProviderWithEmptyOptions() { return [ - ['a:0:{}'], + ['{}'], [''], [null], ]; } + /** + * Test for getTotalBundleItemsPrice() with empty options. + * + * @return void + */ public function testGetTotalBundleItemsPriceWithNoItems() { $storeId = 1; @@ -244,7 +288,7 @@ public function testGetTotalBundleItemsPriceWithNoItems() $dataObjectMock->expects($this->once()) ->method('getValue') - ->willReturn('a:1:{i:0;s:1:"1";}'); + ->willReturn('{"0":1}'); $productTypeMock->expects($this->once()) ->method('getSelectionsByIds') diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php index ed2c8e6c113d8..73fecf8715396 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php @@ -1,6 +1,6 @@ bundleCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\CollectionFactory::class) - ->setMethods(['create']) + ->setMethods( + [ + 'create', + 'addAttributeToSelect', + 'setFlag', + 'setPositionOrder', + 'addStoreFilter', + 'setStoreId', + 'addFilterByRequiredOptions', + 'setOptionIdsFilter', + 'getItemById' + ] + ) ->disableOriginalConstructor() ->getMock(); $this->catalogData = $this->getMockBuilder(\Magento\Catalog\Helper\Data::class) @@ -115,6 +136,18 @@ protected function setUp() ->setMethods(['create']) ->disableOriginalConstructor() ->getMock(); + + $this->catalogRuleProcessor = $this->getMockBuilder( + \Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->serializer = $this->getMockBuilder(Json::class) + ->setMethods(null) + ->disableOriginalConstructor() + ->getMock(); + $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $objectHelper->getObject( \Magento\Bundle\Model\Product\Type::class, @@ -128,7 +161,8 @@ protected function setUp() 'stockRegistry' => $this->stockRegistry, 'stockState' => $this->stockState, 'catalogProduct' => $this->catalogProduct, - 'priceCurrency' => $this->priceCurrency + 'priceCurrency' => $this->priceCurrency, + 'serializer' => $this->serializer ] ); } @@ -201,20 +235,6 @@ public function testPrepareForCartAdvancedWithoutOptions() $product->expects($this->any()) ->method('getTypeInstance') ->willReturn($productType); - $product->expects($this->any()) - ->method('getData') - ->willReturnCallback( - function ($key) use ($optionCollection, $selectionCollection) { - $resultValue = null; - switch ($key) { - case '_cache_instance_options_collection': - $resultValue = $optionCollection; - break; - } - - return $resultValue; - } - ); $optionCollection->expects($this->any()) ->method('appendSelections') ->willReturn([$option]); @@ -1542,7 +1562,7 @@ public function testGetSkuWithoutType() $sku = 'sku'; $itemSku = 'item'; $selectionIds = [1, 2, 3]; - $serializeIds = serialize($selectionIds); + $serializeIds = json_encode($selectionIds); $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) ->setMethods(['__wakeup', 'getData', 'hasCustomOptions', 'getCustomOption']) ->disableOriginalConstructor() @@ -1619,7 +1639,7 @@ public function testGetWeightWithCustomOption() { $weight = 5; $selectionIds = [1, 2, 3]; - $serializeIds = serialize($selectionIds); + $serializeIds = json_encode($selectionIds); $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) ->setMethods(['__wakeup', 'getData', 'hasCustomOptions', 'getCustomOption']) ->disableOriginalConstructor() @@ -1673,7 +1693,7 @@ public function testGetWeightWithSeveralCustomOption() $weight = 5; $qtyOption = 5; $selectionIds = [1, 2, 3]; - $serializeIds = serialize($selectionIds); + $serializeIds = json_encode($selectionIds); $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) ->setMethods(['__wakeup', 'getData', 'hasCustomOptions', 'getCustomOption']) ->disableOriginalConstructor() @@ -1748,7 +1768,7 @@ public function testIsVirtualWithoutCustomOption() public function testIsVirtual() { $selectionIds = [1, 2, 3]; - $serializeIds = serialize($selectionIds); + $serializeIds = json_encode($selectionIds); $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) ->disableOriginalConstructor() @@ -2087,10 +2107,7 @@ public function testIsSalableFalse() */ public function testIsSalableWithoutOptions() { - $optionCollectionMock = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Option\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - + $optionCollectionMock = $this->getOptionCollectionMock([]); $product = new \Magento\Framework\DataObject( [ 'is_salable' => true, @@ -2110,19 +2127,6 @@ public function testIsSalableWithRequiredOptionsTrue() $option1 = $this->getRequiredOptionMock(10, 10); $option2 = $this->getRequiredOptionMock(20, 10); - $this->stockRegistry->method('getStockItem') - ->willReturn($this->getStockItem(true)); - $this->stockState - ->expects($this->at(0)) - ->method('getStockQty') - ->with(10) - ->willReturn(10); - $this->stockState - ->expects($this->at(1)) - ->method('getStockQty') - ->with(20) - ->willReturn(10); - $option3 = $this->getMockBuilder(\Magento\Bundle\Model\Option::class) ->setMethods(['getRequired', 'getOptionId', 'getId']) ->disableOriginalConstructor() @@ -2136,13 +2140,15 @@ public function testIsSalableWithRequiredOptionsTrue() $optionCollectionMock = $this->getOptionCollectionMock([$option1, $option2, $option3]); $selectionCollectionMock = $this->getSelectionCollectionMock([$option1, $option2]); + $this->bundleCollection->expects($this->atLeastOnce()) + ->method('create') + ->will($this->returnValue($selectionCollectionMock)); $product = new \Magento\Framework\DataObject( [ 'is_salable' => true, '_cache_instance_options_collection' => $optionCollectionMock, 'status' => \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED, - '_cache_instance_selections_collection10_20_30' => $selectionCollectionMock ] ); @@ -2174,12 +2180,15 @@ public function testIsSalableWithEmptySelectionsCollection() $optionCollectionMock = $this->getOptionCollectionMock([$option]); $selectionCollectionMock = $this->getSelectionCollectionMock([]); + $this->bundleCollection->expects($this->once()) + ->method('create') + ->will($this->returnValue($selectionCollectionMock)); + $product = new \Magento\Framework\DataObject( [ 'is_salable' => true, '_cache_instance_options_collection' => $optionCollectionMock, 'status' => \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED, - '_cache_instance_selections_collection1' => $selectionCollectionMock ] ); @@ -2189,7 +2198,7 @@ public function testIsSalableWithEmptySelectionsCollection() /** * @return void */ - public function testIsSalableWithRequiredOptionsOutOfStock() + public function nottestIsSalableWithRequiredOptionsOutOfStock() { $option1 = $this->getRequiredOptionMock(10, 10); $option1 @@ -2218,58 +2227,21 @@ public function testIsSalableWithRequiredOptionsOutOfStock() $optionCollectionMock = $this->getOptionCollectionMock([$option1, $option2]); $selectionCollectionMock = $this->getSelectionCollectionMock([$option1, $option2]); + $this->bundleCollection->expects($this->once()) + ->method('create') + ->will($this->returnValue($selectionCollectionMock)); $product = new \Magento\Framework\DataObject( [ 'is_salable' => true, '_cache_instance_options_collection' => $optionCollectionMock, 'status' => \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED, - '_cache_instance_selections_collection10_20' => $selectionCollectionMock ] ); $this->assertFalse($this->model->isSalable($product)); } - /** - * @return void - */ - public function testIsSalableNoManageStock() - { - $option1 = $this->getRequiredOptionMock(10, 10); - $option2 = $this->getRequiredOptionMock(20, 10); - - $stockItem = $this->getStockItem(true); - - $this->stockRegistry->method('getStockItem') - ->willReturn($stockItem); - - $this->stockState - ->expects($this->at(0)) - ->method('getStockQty') - ->with(10) - ->willReturn(10); - $this->stockState - ->expects($this->at(1)) - ->method('getStockQty') - ->with(20) - ->willReturn(10); - - $optionCollectionMock = $this->getOptionCollectionMock([$option1, $option2]); - $selectionCollectionMock = $this->getSelectionCollectionMock([$option1, $option2]); - - $product = new \Magento\Framework\DataObject( - [ - 'is_salable' => true, - '_cache_instance_options_collection' => $optionCollectionMock, - 'status' => \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED, - '_cache_instance_selections_collection10_20' => $selectionCollectionMock - ] - ); - - $this->assertTrue($this->model->isSalable($product)); - } - /** * @param int $id * @param int $selectionQty @@ -2317,7 +2289,7 @@ private function getSelectionCollectionMock(array $selectedOptions) { $selectionCollectionMock = $this->getMockBuilder( \Magento\Bundle\Model\ResourceModel\Selection\Collection::class - )->setMethods(['getItems', 'getIterator']) + ) ->disableOriginalConstructor() ->getMock(); @@ -2465,36 +2437,29 @@ public function testGetSelectionsCollection() ] ) ->getMock(); - $selectionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class) - ->disableOriginalConstructor() - ->setMethods( - [ - 'addAttributeToSelect', - 'setFlag', - 'setPositionOrder', - 'addStoreFilter', - 'setStoreId', - 'addFilterByRequiredOptions', - 'setOptionIdsFilter', - 'joinPrices' - ] - ) - ->getMock(); $store = $this->getMockBuilder(\Magento\Store\Model\Store::class) ->disableOriginalConstructor() ->setMethods(['getWebsiteId']) ->getMock(); - $product->expects($this->once()) - ->method('hasData') - ->with('_cache_instance_selections_collection1_2_3') - ->willReturn(false); $product->expects($this->once())->method('getStoreId')->willReturn('store_id'); - $product->expects($this->at(2)) - ->method('getData') - ->with('_cache_instance_store_filter') - ->willReturn($selectionCollection); + $selectionCollection = $this->getSelectionCollection(); $this->bundleCollection->expects($this->once())->method('create')->willReturn($selectionCollection); + $this->storeManager->expects($this->once())->method('getStore')->willReturn($store); + $store->expects($this->once())->method('getWebsiteId')->willReturn('website_id'); + $selectionCollection->expects($this->any())->method('joinPrices')->with('website_id')->willReturnSelf(); + + $this->assertEquals($selectionCollection, $this->model->getSelectionsCollection($optionIds, $product)); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getSelectionCollection() + { + $selectionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class) + ->disableOriginalConstructor() + ->getMock(); $selectionCollection->expects($this->any())->method('addAttributeToSelect')->willReturnSelf(); $selectionCollection->expects($this->any())->method('setFlag')->willReturnSelf(); $selectionCollection->expects($this->any())->method('setPositionOrder')->willReturnSelf(); @@ -2502,19 +2467,10 @@ public function testGetSelectionsCollection() $selectionCollection->expects($this->any())->method('setStoreId')->willReturnSelf(); $selectionCollection->expects($this->any())->method('addFilterByRequiredOptions')->willReturnSelf(); $selectionCollection->expects($this->any())->method('setOptionIdsFilter')->willReturnSelf(); - $this->storeManager->expects($this->once())->method('getStore')->willReturn($store); - $store->expects($this->once())->method('getWebsiteId')->willReturn('website_id'); - $selectionCollection->expects($this->any())->method('joinPrices')->with('website_id')->willReturnSelf(); - $product->expects($this->once()) - ->method('setData') - ->with('_cache_instance_selections_collection1_2_3', $selectionCollection) - ->willReturnSelf(); - $product->expects($this->at(4)) - ->method('getData') - ->with('_cache_instance_selections_collection1_2_3') - ->willReturn($selectionCollection); + $selectionCollection->expects($this->any())->method('addPriceData')->willReturnSelf(); + $selectionCollection->expects($this->any())->method('addTierPriceData')->willReturnSelf(); - $this->assertEquals($selectionCollection, $this->model->getSelectionsCollection($optionIds, $product)); + return $selectionCollection; } public function testProcessBuyRequest() @@ -2548,7 +2504,10 @@ public function testGetProductsToPurchaseByReqGroups() ->disableOriginalConstructor() ->setMethods(['getId', 'getRequired']) ->getMock(); - $selectionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class) + $selectionCollection = $this->getSelectionCollection(); + $this->bundleCollection->expects($this->once())->method('create')->willReturn($selectionCollection); + + $selectionItem = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->disableOriginalConstructor() ->getMock(); @@ -2559,13 +2518,13 @@ public function testGetProductsToPurchaseByReqGroups() ->willReturn($dbResourceMock); $dbResourceMock->expects($this->once())->method('getItems')->willReturn([$item]); $item->expects($this->once())->method('getId')->willReturn('itemId'); - $product->expects($this->at(3)) - ->method('getData') - ->with('_cache_instance_selections_collectionitemId') - ->willReturn([$selectionCollection]); $item->expects($this->once())->method('getRequired')->willReturn(true); - $this->assertEquals([[$selectionCollection]], $this->model->getProductsToPurchaseByReqGroups($product)); + $selectionCollection + ->expects($this->any()) + ->method('getIterator') + ->willReturn(new \ArrayIterator([$selectionItem])); + $this->assertEquals([[$selectionItem]], $this->model->getProductsToPurchaseByReqGroups($product)); } public function testGetSearchableData() @@ -2598,14 +2557,17 @@ public function testHasOptions() ->disableOriginalConstructor() ->setMethods(['getAllIds']) ->getMock(); - $selectionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class) - ->disableOriginalConstructor() - ->getMock(); + $selectionCollection = $this->getSelectionCollection(); + $selectionCollection + ->expects($this->any()) + ->method('count') + ->willReturn(1); + $this->bundleCollection->expects($this->once())->method('create')->willReturn($selectionCollection); - $product->expects($this->once())->method('getStoreId')->willReturn('storeId'); + $product->expects($this->any())->method('getStoreId')->willReturn(0); $product->expects($this->once()) ->method('setData') - ->with('_cache_instance_store_filter', 'storeId') + ->with('_cache_instance_store_filter', 0) ->willReturnSelf(); $product->expects($this->any())->method('hasData')->willReturn(true); $product->expects($this->at(3)) @@ -2613,11 +2575,171 @@ public function testHasOptions() ->with('_cache_instance_options_collection') ->willReturn($optionCollection); $optionCollection->expects($this->once())->method('getAllIds')->willReturn(['ids']); - $product->expects($this->at(5)) - ->method('getData') - ->with('_cache_instance_selections_collectionids') - ->willReturn([$selectionCollection]); $this->assertTrue($this->model->hasOptions($product)); } + + /** + * Bundle product without options should not be possible to buy. + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Please specify product option + */ + public function testCheckProductBuyStateEmptyOptionsException() + { + $this->mockBundleCollection(); + $product = $this->getProductMock(); + $product->method('getCustomOption')->willReturnMap([ + ['bundle_selection_ids', new DataObject(['value' => ''])], + ['info_buyRequest', new DataObject(['value' => json_encode(['bundle_option' => ''])])], + ]); + $product->setCustomOption(json_encode([])); + + $this->model->checkProductBuyState($product); + } + + /** + * Previously selected options are not more available for buying. + * + * @param object $element + * @param string $expectedMessage + * @param bool $check + * + * @throws LocalizedException + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @dataProvider notAvailableOptionProvider + */ + public function testCheckProductBuyStateMissedOptionException($element, $expectedMessage, $check) + { + $this->mockBundleCollection(); + $product = $this->getProductMock(); + $product->method('getCustomOption')->willReturnMap([ + ['bundle_selection_ids', new DataObject(['value' => json_encode([1])])], + ['info_buyRequest', new DataObject(['value' => json_encode(['bundle_option' => [1]])])], + ]); + $product->setCustomOption(json_encode([])); + + $this->bundleCollection->method('getItemById')->willReturn($element); + $this->catalogProduct->setSkipSaleableCheck($check); + + try { + $this->model->checkProductBuyState($product); + } catch (LocalizedException $e) { + $this->assertContains( + $expectedMessage, + $e->getMessage() + ); + throw $e; + } + } + + /** + * In case of missed selection for required options, bundle product should be not able to buy. + * + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testCheckProductBuyStateRequiredOptionException() + { + $this->mockBundleCollection(); + $product = $this->getProductMock(); + $product->method('getCustomOption')->willReturnMap([ + ['bundle_selection_ids', new DataObject(['value' => json_encode([])])], + ['info_buyRequest', new DataObject(['value' => json_encode(['bundle_option' => [1]])])], + ]); + $product->setCustomOption(json_encode([])); + + $falseSelection = $this->getMockBuilder(Selection::class) + ->disableOriginalConstructor() + ->setMethods(['isSalable']) + ->getMock(); + $falseSelection->method('isSalable')->willReturn(false); + + $this->bundleCollection->method('getItemById')->willReturn($falseSelection); + $this->catalogProduct->setSkipSaleableCheck(false); + + try { + $this->model->checkProductBuyState($product); + } catch (LocalizedException $e) { + $this->assertContains( + 'Please select all required options', + $e->getMessage() + ); + + throw $e; + } + } + + /** + * Prepare product mock for testing. + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function getProductMock() + { + $product = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->setMethods([ + '_wakeup', + 'getHasOptions', + 'getId', + 'getStoreId', + 'getCustomOption', + 'getTypeInstance', + 'setStoreFilter', + ]) + ->getMock(); + $product->method('getTypeInstance')->willReturn($product); + $product->method('setStoreFilter')->willReturn($product); + $optionCollectionCache = new DataObject(); + $optionCollectionCache->setAllIds([]); + $optionCollectionCache->setItems([ + new DataObject([ + 'required' => true, + 'id' => 1 + ]), + ]); + $product->setData('_cache_instance_options_collection', $optionCollectionCache); + return $product; + } + + /** + * Preparation mocks for checkProductsBuyState. + */ + public function mockBundleCollection() + { + $this->bundleCollection->method('create')->willReturn($this->bundleCollection); + $this->bundleCollection->method('addAttributeToSelect')->willReturn($this->bundleCollection); + $this->bundleCollection->method('setFlag')->willReturn($this->bundleCollection); + $this->bundleCollection->method('setPositionOrder')->willReturn($this->bundleCollection); + $this->bundleCollection->method('addStoreFilter')->willReturn($this->bundleCollection); + $this->bundleCollection->method('setStoreId')->willReturn($this->bundleCollection); + $this->bundleCollection->method('addFilterByRequiredOptions')->willReturn($this->bundleCollection); + $this->bundleCollection->method('setOptionIdsFilter')->willReturn($this->bundleCollection); + } + + /** + * Data provider for not available option. + * @return array + */ + public function notAvailableOptionProvider() + { + $falseSelection = $this->getMockBuilder(Selection::class) + ->disableOriginalConstructor() + ->setMethods(['isSalable']) + ->getMock(); + $falseSelection->method('isSalable')->willReturn(false); + return [ + [ + false, + 'The required options you selected are not available', + false, + ], + [ + $falseSelection, + 'The required options you selected are not available', + false + ], + ]; + } } diff --git a/app/code/Magento/Bundle/Test/Unit/Model/ProductOptionProcessorTest.php b/app/code/Magento/Bundle/Test/Unit/Model/ProductOptionProcessorTest.php index d7f8e69b9dbee..3322e24a5bd5c 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/ProductOptionProcessorTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/ProductOptionProcessorTest.php @@ -1,6 +1,6 @@ orderItem = $this->getMock( @@ -24,7 +27,13 @@ protected function setUp() ); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->model = $objectManager->getObject(\Magento\Bundle\Model\Sales\Order\Pdf\Items\Shipment::class); + $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class); + $this->model = $objectManager->getObject( + \Magento\Bundle\Model\Sales\Order\Pdf\Items\Shipment::class, + [ + 'serializer' => $this->serializer + ] + ); } /** @@ -234,21 +243,25 @@ public function getBundleOptionsDataProvider() ]; } - /** - * @dataProvider getSelectionAttributesDataProvider - */ - public function testGetSelectionAttributes($productOptions, $result) + public function testGetSelectionAttributes() { - $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($productOptions)); - $this->assertSame($result, $this->model->getSelectionAttributes($this->orderItem)); + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue([])); + $this->assertNull($this->model->getSelectionAttributes($this->orderItem)); } - public function getSelectionAttributesDataProvider() + public function testGetSelectionAttributesWithBundle() { - return [ - [[], null], - [['bundle_selection_attributes' => 'a:1:{i:0;i:1;}'], [0 => 1]], - ]; + $bundleAttributes = 'Serialized value'; + $options = ['bundle_selection_attributes' => $bundleAttributes]; + $unserializedResult = 'result of "bundle_selection_attributes" unserialization'; + + $this->serializer->expects($this->any()) + ->method('unserialize') + ->with($bundleAttributes) + ->will($this->returnValue($unserializedResult)); + $this->orderItem->expects($this->any())->method('getProductOptions')->will($this->returnValue($options)); + + $this->assertEquals($unserializedResult, $this->model->getSelectionAttributes($this->orderItem)); } public function testGetOrderOptions() diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Adjustment/CalculatorTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Adjustment/CalculatorTest.php index 73bbf1bc5d0d2..9efb71d235bad 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Adjustment/CalculatorTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Adjustment/CalculatorTest.php @@ -1,6 +1,6 @@ saleableItem = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) - ->setMethods(['getPriceInfo', 'getPriceType', '__wakeup', 'getStore']) + ->setMethods(['getPriceInfo', 'getPriceType', '__wakeup', 'getStore', 'getTypeInstance']) ->disableOriginalConstructor() ->getMock(); + $priceCurrency = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class)->getMock(); $priceInfo = $this->getMock(\Magento\Framework\Pricing\PriceInfo\Base::class, [], [], '', false); $priceInfo->expects($this->any())->method('getPrice')->will( @@ -112,6 +118,10 @@ function ($type) { ->disableOriginalConstructor() ->getMock(); + $this->selectionPriceListProvider = $this->getMockBuilder( + \Magento\Bundle\Pricing\Adjustment\SelectionPriceListProviderInterface::class + )->getMock(); + $this->model = (new ObjectManager($this))->getObject(\Magento\Bundle\Pricing\Adjustment\Calculator::class, [ 'calculator' => $this->baseCalculator, @@ -119,6 +129,7 @@ function ($type) { 'bundleSelectionFactory' => $this->selectionFactory, 'taxHelper' => $this->taxData, 'priceCurrency' => $priceCurrency, + 'selectionPriceListProvider' => $this->selectionPriceListProvider ] ); } @@ -137,6 +148,7 @@ public function testEmptySelectionPriceList() */ public function testGetterAmount($amountForBundle, $optionList, $expectedResult) { + $searchMin = $expectedResult['isMinAmount']; $this->baseCalculator->expects($this->atLeastOnce())->method('getAmount') ->with($this->baseAmount, $this->saleableItem) ->will($this->returnValue($this->createAmountMock($amountForBundle))); @@ -145,8 +157,14 @@ public function testGetterAmount($amountForBundle, $optionList, $expectedResult) foreach ($optionList as $optionData) { $options[] = $this->createOptionMock($optionData); } + + $optionSelections = []; + foreach ($options as $option) { + $optionSelections = array_merge($optionSelections, $option->getSelections()); + } + $this->selectionPriceListProvider->expects($this->any())->method('getPriceList')->willReturn($optionSelections); + $price = $this->getMock(\Magento\Bundle\Pricing\Price\BundleOptionPrice::class, [], [], '', false); - $price->expects($this->atLeastOnce())->method('getOptions')->will($this->returnValue($options)); $this->priceMocks[Price\BundleOptionPrice::PRICE_CODE] = $price; // Price type of saleable items @@ -158,7 +176,7 @@ public function testGetterAmount($amountForBundle, $optionList, $expectedResult) $this->amountFactory->expects($this->atLeastOnce())->method('create') ->with($expectedResult['fullAmount'], $expectedResult['adjustments']); - if ($expectedResult['isMinAmount']) { + if ($searchMin) { $this->model->getAmount($this->baseAmount, $this->saleableItem); } else { $this->model->getMaxAmount($this->baseAmount, $this->saleableItem); @@ -287,21 +305,7 @@ protected function getCaseWithMinAmount() 'required' => '1', ], 'selections' => [ - 'first product selection' => [ - 'data' => ['price' => 70.], - 'amount' => [ - 'adjustmentsAmounts' => ['tax' => 8, 'weee' => 10], - 'amount' => 18, - ], - ], - 'second product selection' => [ - 'data' => ['price' => 80.], - 'amount' => [ - 'adjustmentsAmounts' => ['tax' => 18], - 'amount' => 28, - ], - ], - 'third product selection with the lowest price' => [ + 'selection with the lowest price' => [ 'data' => ['price' => 50.], 'amount' => [ 'adjustmentsAmounts' => ['tax' => 8, 'weee' => 10], @@ -351,13 +355,6 @@ protected function getCaseWithMaxAmount() 'amount' => 8, ], ], - 'second product selection' => [ - 'data' => ['price' => 80.], - 'amount' => [ - 'adjustmentsAmounts' => ['tax' => 18], - 'amount' => 8, - ], - ], ] ], // second option with multiselection @@ -471,13 +468,6 @@ protected function getCaseMinAmountWithoutRequiredOptions() 'amount' => 8, ], ], - 'second product selection' => [ - 'data' => ['price' => 30.], - 'amount' => [ - 'adjustmentsAmounts' => ['tax' => 10], - 'amount' => 12, - ], - ], ] ], // second option @@ -492,20 +482,6 @@ protected function getCaseMinAmountWithoutRequiredOptions() 'required' => '0', ], 'selections' => [ - 'first product selection' => [ - 'data' => ['price' => 25.], - 'amount' => [ - 'adjustmentsAmounts' => ['tax' => 8], - 'amount' => 9, - ], - ], - 'second product selection' => [ - 'data' => ['price' => 35.], - 'amount' => [ - 'adjustmentsAmounts' => ['tax' => 10], - 'amount' => 10, - ], - ], ] ], ], diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php index 339bb532e6e40..7a7ad3e317b9f 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php @@ -1,6 +1,6 @@ create($this->bundleMock, $this->selectionMock, 2., ['test' => 'some value']) ); } - - /** - * @expectedException \InvalidArgumentException - */ - public function testCreateException() - { - $this->objectManagerMock->expects($this->once()) - ->method('create') - ->with( - $this->equalTo(BundleSelectionFactory::SELECTION_CLASS_DEFAULT), - $this->equalTo( - [ - 'test' => 'some value', - 'bundleProduct' => $this->bundleMock, - 'saleableItem' => $this->selectionMock, - 'quantity' => 2., - ] - ) - ) - ->will($this->returnValue(new \stdClass())); - $this->bundleSelectionFactory->create($this->bundleMock, $this->selectionMock, 2., ['test' => 'some value']); - } } diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php index 5cb5ea550ab49..5837398df7627 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php @@ -1,6 +1,6 @@ getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); $amount->expects($this->once())->method('getBaseAmount')->willReturn($baseAmount); + $price = $this->getMock(\Magento\Framework\Pricing\Price\PriceInterface::class); + $price->expects($this->any()) + ->method('getValue') + ->will($this->returnValue($basePrice)); + $this->priceInfo->expects($this->any()) + ->method('getPrice') + ->will($this->returnValue($price)); $this->assertEquals($savePercent, $this->model->getSavePercent($amount)); } @@ -200,10 +208,8 @@ public function testGetSavePercent($baseAmount, $savePercent) public function providerForTestGetSavePercent() { return [ - 'no fraction' => [10.0000, 10], - 'lower half' => [10.1234, 10], - 'half way' => [10.5000, 11], - 'upper half' => [10.6789, 11], + 'no fraction' => [9.0000, 10], + 'lower half' => [9.1234, 9], ]; } } diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Render/FinalPriceBoxTest.php index 0a30bd0a027de..5649e268a2d5f 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Render/FinalPriceBoxTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Render/FinalPriceBoxTest.php @@ -1,6 +1,6 @@ removeFixedTierPrice($meta); $path = $this->arrayManager->findPath(static::CODE_BUNDLE_DATA, $meta, null, 'children'); $meta = $this->arrayManager->merge( @@ -178,6 +181,45 @@ public function modifyMeta(array $meta) return $meta; } + /** + * Remove option with fixed tier price from config. + * + * @param array $meta + * @return array + */ + private function removeFixedTierPrice(array $meta) + { + $tierPricePath = $this->arrayManager->findPath( + ProductAttributeInterface::CODE_TIER_PRICE, + $meta, + null, + 'children' + ); + $pricePath = $this->arrayManager->findPath( + ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE, + $meta, + $tierPricePath + ); + $pricePath = $this->arrayManager->slicePath($pricePath, 0, -1) . '/value_type/arguments/data/options'; + + $price = $this->arrayManager->get($pricePath, $meta); + if ($price) { + $meta = $this->arrayManager->remove($pricePath, $meta); + foreach ($price as $key => $item) { + if ($item['value'] == ProductPriceOptionsInterface::VALUE_FIXED) { + unset($price[$key]); + } + } + $meta = $this->arrayManager->merge( + $this->arrayManager->slicePath($pricePath, 0, -1), + $meta, + ['options' => $price] + ); + } + + return $meta; + } + /** * {@inheritdoc} */ @@ -268,15 +310,12 @@ protected function getBundleOptions() 'arguments' => [ 'data' => [ 'config' => [ - 'componentType' => 'dynamicRows', + 'componentType' => Container::NAME, + 'component' => 'Magento_Bundle/js/components/bundle-dynamic-rows', 'template' => 'ui/dynamic-rows/templates/collapsible', - 'label' => '', 'additionalClasses' => 'admin__field-wide', - 'collapsibleHeader' => true, - 'columnsHeader' => false, - 'deleteProperty' => false, - 'addButton' => false, 'dataScope' => 'data.bundle_options', + 'bundleSelectionsName' => 'product_bundle_container.bundle_selections' ], ], ], @@ -318,14 +357,11 @@ protected function getBundleOptions() 'arguments' => [ 'data' => [ 'config' => [ - 'componentType' => DynamicRows::NAME, - 'label' => '', + 'componentType' => Container::NAME, + 'component' => 'Magento_Bundle/js/components/bundle-dynamic-rows-grid', 'sortOrder' => 50, 'additionalClasses' => 'admin__field-wide', - 'component' => 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid', 'template' => 'ui/dynamic-rows/templates/default', - 'columnsHeader' => false, - 'columnsHeaderAfterRender' => true, 'provider' => 'product_form.product_form_data_source', 'dataProvider' => '${ $.dataScope }' . '.bundle_button_proxy', 'identificationDRProperty' => 'product_id', @@ -342,11 +378,8 @@ protected function getBundleOptions() 'selection_price_value' => '', 'selection_qty' => '', ], - 'links' => [ - 'insertData' => '${ $.provider }:${ $.dataProvider }' - ], - 'source' => 'product', - 'addButton' => false, + 'links' => ['insertData' => '${ $.provider }:${ $.dataProvider }'], + 'source' => 'product' ], ], ], @@ -563,7 +596,7 @@ protected function getBundleSelections() 'componentType' => Container::NAME, 'isTemplate' => true, 'component' => 'Magento_Ui/js/dynamic-rows/record', - 'is_collection' => true, + 'is_collection' => true ], ], ], @@ -588,10 +621,7 @@ protected function getBundleSelections() 'prefer' => 'radio', 'value' => '0', 'sortOrder' => 50, - 'valueMap' => [ - 'false' => '0', - 'true' => '1' - ] + 'valueMap' => ['false' => '0', 'true' => '1'] ], ], ], @@ -642,7 +672,8 @@ protected function getBundleSelections() 'sortOrder' => 100, 'validation' => [ 'required-entry' => true, - 'validate-zero-or-greater' => true + 'validate-number' => true, + 'validate-greater-than-zero' => true ], 'imports' => [ 'isInteger' => '${ $.provider }:${ $.parentScope }.selection_qty_is_integer' diff --git a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePrice.php b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePrice.php index 15643eaa8a70e..9cfb3b99a135d 100644 --- a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePrice.php +++ b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePrice.php @@ -1,6 +1,6 @@ ($productLink->getIsDefault()) ? '1' : '0', 'selection_price_value' => $productLink->getPrice(), 'selection_price_type' => $productLink->getPriceType(), - 'selection_qty' => (bool)$integerQty ? (int)$productLink->getQty() : $productLink->getQty(), + 'selection_qty' => $integerQty ? (int)$productLink->getQty() : $productLink->getQty(), 'selection_can_change_qty' => $productLink->getCanChangeQuantity(), 'selection_qty_is_integer' => (bool)$integerQty, 'position' => $productLink->getPosition(), diff --git a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/StockData.php b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/StockData.php index 421e7b4d19989..2bd00bfaa9705 100644 --- a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/StockData.php +++ b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/StockData.php @@ -1,6 +1,6 @@ @@ -27,11 +27,11 @@ Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\Composite - 125 + 180 Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\StockData - 126 + 190 diff --git a/app/code/Magento/Bundle/etc/adminhtml/events.xml b/app/code/Magento/Bundle/etc/adminhtml/events.xml index 3e1de66c1fdd3..cd8af005694ea 100644 --- a/app/code/Magento/Bundle/etc/adminhtml/events.xml +++ b/app/code/Magento/Bundle/etc/adminhtml/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/adminhtml/routes.xml b/app/code/Magento/Bundle/etc/adminhtml/routes.xml index e140d1b6875a4..d2e7c9c3b20f9 100644 --- a/app/code/Magento/Bundle/etc/adminhtml/routes.xml +++ b/app/code/Magento/Bundle/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/catalog_attributes.xml b/app/code/Magento/Bundle/etc/catalog_attributes.xml index 832ba71237c0b..8c45aaab6c46f 100644 --- a/app/code/Magento/Bundle/etc/catalog_attributes.xml +++ b/app/code/Magento/Bundle/etc/catalog_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/config.xml b/app/code/Magento/Bundle/etc/config.xml index abaed7a879f2b..0016210cd149d 100644 --- a/app/code/Magento/Bundle/etc/config.xml +++ b/app/code/Magento/Bundle/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml index b89e290c06814..e2a913acd50b7 100644 --- a/app/code/Magento/Bundle/etc/di.xml +++ b/app/code/Magento/Bundle/etc/di.xml @@ -1,7 +1,7 @@ @@ -14,6 +14,7 @@ + @@ -129,4 +130,11 @@ + + + + bundle + + + diff --git a/app/code/Magento/Bundle/etc/extension_attributes.xml b/app/code/Magento/Bundle/etc/extension_attributes.xml index 3819e892e6ff1..d23dfc71b39fc 100644 --- a/app/code/Magento/Bundle/etc/extension_attributes.xml +++ b/app/code/Magento/Bundle/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/frontend/di.xml b/app/code/Magento/Bundle/etc/frontend/di.xml index acaf67ac82e5e..084f681df7e03 100644 --- a/app/code/Magento/Bundle/etc/frontend/di.xml +++ b/app/code/Magento/Bundle/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/frontend/events.xml b/app/code/Magento/Bundle/etc/frontend/events.xml index ce21acda965de..d08cdb4bcc997 100644 --- a/app/code/Magento/Bundle/etc/frontend/events.xml +++ b/app/code/Magento/Bundle/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/module.xml b/app/code/Magento/Bundle/etc/module.xml index 982a33d00bc6b..878af07761b42 100644 --- a/app/code/Magento/Bundle/etc/module.xml +++ b/app/code/Magento/Bundle/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Bundle/etc/pdf.xml b/app/code/Magento/Bundle/etc/pdf.xml index 085e7946cb7d6..912aa1426efa1 100644 --- a/app/code/Magento/Bundle/etc/pdf.xml +++ b/app/code/Magento/Bundle/etc/pdf.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/product_types.xml b/app/code/Magento/Bundle/etc/product_types.xml index c3f909afbeabe..6168189a3b4e3 100644 --- a/app/code/Magento/Bundle/etc/product_types.xml +++ b/app/code/Magento/Bundle/etc/product_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/sales.xml b/app/code/Magento/Bundle/etc/sales.xml index 74e5647051dec..3094eb6bfecfa 100644 --- a/app/code/Magento/Bundle/etc/sales.xml +++ b/app/code/Magento/Bundle/etc/sales.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/webapi.xml b/app/code/Magento/Bundle/etc/webapi.xml index 6e31986be7b8f..69124309687a3 100644 --- a/app/code/Magento/Bundle/etc/webapi.xml +++ b/app/code/Magento/Bundle/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/webapi_rest/di.xml b/app/code/Magento/Bundle/etc/webapi_rest/di.xml index acaf67ac82e5e..084f681df7e03 100644 --- a/app/code/Magento/Bundle/etc/webapi_rest/di.xml +++ b/app/code/Magento/Bundle/etc/webapi_rest/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/etc/webapi_soap/di.xml b/app/code/Magento/Bundle/etc/webapi_soap/di.xml index acaf67ac82e5e..084f681df7e03 100644 --- a/app/code/Magento/Bundle/etc/webapi_soap/di.xml +++ b/app/code/Magento/Bundle/etc/webapi_soap/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/registration.php b/app/code/Magento/Bundle/registration.php index 48ae2414286eb..53f3657ae0519 100644 --- a/app/code/Magento/Bundle/registration.php +++ b/app/code/Magento/Bundle/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_view.xml b/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_view.xml index 34975692a948b..2f9812faff659 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_view.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_view.xml @@ -1,14 +1,14 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_bundle.xml b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_bundle.xml index 14ab43a776bbb..d0fdb184355d7 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_bundle.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_bundle.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml index 251a2ddd68af6..a496ea7538923 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_view_type_bundle.xml b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_view_type_bundle.xml index 370ef3cf8afca..15374cb987d36 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_view_type_bundle.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_view_type_bundle.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/customer_index_wishlist.xml b/app/code/Magento/Bundle/view/adminhtml/layout/customer_index_wishlist.xml index b7a0c9d03e16e..7e37070109921 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/customer_index_wishlist.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/customer_index_wishlist.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml index f3962e20d4435..99fdab5a7e9f4 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml index f3962e20d4435..99fdab5a7e9f4 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml index 5f2c852416e04..323aba1d186e6 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml index 9b37d8286fdcb..b03ce7a9cb451 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml index 9b37d8286fdcb..b03ce7a9cb451 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml index 752031796631f..34c3470cf06a7 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml index 2c6a8fe93caa9..62f0305194fa9 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/catalog/product/edit/tab/attributes/extend.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/catalog/product/edit/tab/attributes/extend.phtml index 0dff5ef370825..84e87afd48180 100644 --- a/app/code/Magento/Bundle/view/adminhtml/templates/catalog/product/edit/tab/attributes/extend.phtml +++ b/app/code/Magento/Bundle/view/adminhtml/templates/catalog/product/edit/tab/attributes/extend.phtml @@ -1,6 +1,6 @@ -decorateArray($block->getOptions()); ?> +decorateArray($block->getOptions(true)); ?>
    diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/type/checkbox.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/type/checkbox.phtml index f74f4e3435c67..970b1c38642af 100644 --- a/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/type/checkbox.phtml +++ b/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/type/checkbox.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/sales/creditmemo/create/items/renderer.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/sales/creditmemo/create/items/renderer.phtml index 8fddd0798f7b4..41923c4826432 100644 --- a/app/code/Magento/Bundle/view/adminhtml/templates/sales/creditmemo/create/items/renderer.phtml +++ b/app/code/Magento/Bundle/view/adminhtml/templates/sales/creditmemo/create/items/renderer.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Bundle/view/adminhtml/web/css/bundle-product.css b/app/code/Magento/Bundle/view/adminhtml/web/css/bundle-product.css index 3503d6050e777..d5aed8a7d652e 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/css/bundle-product.css +++ b/app/code/Magento/Bundle/view/adminhtml/web/css/bundle-product.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js b/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js index a4e47177bdf22..53b08e43614a0 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-product.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-type-handler.js b/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-type-handler.js index 12dda7d3a148c..7f4a57cb530da 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-type-handler.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/bundle-type-handler.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true expr:true*/ diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js index b7a05076ae268..9c2432bade43f 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-checkbox.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js new file mode 100644 index 0000000000000..6265394cf38e3 --- /dev/null +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows-grid.js @@ -0,0 +1,59 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid' +], function (_, dynamicRowsGrid) { + 'use strict'; + + return dynamicRowsGrid.extend({ + defaults: { + label: '', + columnsHeader: false, + columnsHeaderAfterRender: true, + addButton: false + }, + + /** + * Initialize elements from grid + * + * @param {Array} data + * + * @returns {Object} Chainable. + */ + initElements: function (data) { + var newData = this.getNewData(data), + recordIndex; + + this.parsePagesData(data); + + if (newData.length) { + if (this.insertData().length) { + recordIndex = data.length - newData.length - 1; + + _.each(newData, function (newRecord) { + this.processingAddChild(newRecord, ++recordIndex, newRecord[this.identificationProperty]); + }, this); + } + } + + return this; + }, + + /** + * Mapping value from grid + * + * @param {Array} data + */ + mappingValue: function (data) { + if (_.isEmpty(data)) { + return; + } + + this._super(); + } + }); +}); diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows.js new file mode 100644 index 0000000000000..4bbd1b3e4da20 --- /dev/null +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-dynamic-rows.js @@ -0,0 +1,98 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'mageUtils', + 'uiRegistry', + 'Magento_Ui/js/dynamic-rows/dynamic-rows' +], function (_, utils, registry, dynamicRows) { + 'use strict'; + + return dynamicRows.extend({ + defaults: { + label: '', + collapsibleHeader: true, + columnsHeader: false, + deleteProperty: false, + addButton: false + }, + + /** + * Set new data to dataSource, + * delete element + * + * @param {Array} data - record data + */ + _updateData: function (data) { + var elems = _.clone(this.elems()), + path, + dataArr, + optionBaseData; + + dataArr = this.recordData.splice(this.startIndex, this.recordData().length - this.startIndex); + dataArr.splice(0, this.pageSize); + elems = _.sortBy(this.elems(), function (elem) { + return ~~elem.index; + }); + + data.concat(dataArr).forEach(function (rec, idx) { + if (elems[idx]) { + elems[idx].recordId = rec[this.identificationProperty]; + } + + if (!rec.position) { + rec.position = this.maxPosition; + this.setMaxPosition(); + } + + path = this.dataScope + '.' + this.index + '.' + (this.startIndex + idx); + optionBaseData = _.pick(rec, function (value) { + return !_.isObject(value); + }); + this.source.set(path, optionBaseData); + this.source.set(path + '.bundle_button_proxy', []); + this.source.set(path + '.bundle_selections', []); + this.removeBundleItemsFromOption(idx); + _.each(rec['bundle_selections'], function (obj, index) { + this.source.set(path + '.bundle_button_proxy' + '.' + index, rec['bundle_button_proxy'][index]); + this.source.set(path + '.bundle_selections' + '.' + index, obj); + }, this); + }, this); + + this.elems(elems); + }, + + /** + * Removes nested dynamic-rows-grid rendered records from option + * + * @param {Number|String} index - element index + */ + removeBundleItemsFromOption: function (index) { + var bundleSelections = registry.get(this.name + '.' + index + '.' + this.bundleSelectionsName), + bundleSelectionsLength = (bundleSelections.elems() || []).length, + i; + + if (bundleSelectionsLength) { + for (i = 0; i < bundleSelectionsLength; i++) { + bundleSelections.elems()[0].destroy(); + } + } + }, + + /** + * {@inheritdoc} + */ + processingAddChild: function (ctx, index, prop) { + var recordIds = _.map(this.recordData(), function (rec) { + return parseInt(rec['record_id'], 10); + }), + maxRecordId = _.max(recordIds); + + prop = maxRecordId > -1 ? maxRecordId + 1 : prop; + this._super(ctx, index, prop); + } + }); +}); diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-input-type.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-input-type.js index 14dd426ed02aa..cee0489cc901a 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-input-type.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-input-type.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js index a52d4e8a4683b..d5be0a19b597d 100644 --- a/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js +++ b/app/code/Magento/Bundle/view/adminhtml/web/js/components/bundle-option-qty.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -11,16 +11,28 @@ define([ return Abstract.extend({ defaults: { valueUpdate: 'input', - isInteger: true + isInteger: true, + validation: { + 'validate-number': true + } }, /** - * update event + * @inheritdoc */ onUpdate: function () { - this.validation['validate-number'] = true; this.validation['validate-digits'] = this.isInteger; - this.validate(); + this._super(); + }, + + /** + * @inheritdoc + */ + hasChanged: function () { + var notEqual = this.value() !== this.initialValue.toString(); + + return !this.visible() ? false : notEqual; } + }); }); diff --git a/app/code/Magento/Bundle/view/base/layout/catalog_product_prices.xml b/app/code/Magento/Bundle/view/base/layout/catalog_product_prices.xml index 92d76cdfaa580..5f7d22ba2650b 100644 --- a/app/code/Magento/Bundle/view/base/layout/catalog_product_prices.xml +++ b/app/code/Magento/Bundle/view/base/layout/catalog_product_prices.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/base/templates/product/price/final_price.phtml b/app/code/Magento/Bundle/view/base/templates/product/price/final_price.phtml index 4c11b0ba1fe50..efd75677d3061 100644 --- a/app/code/Magento/Bundle/view/base/templates/product/price/final_price.phtml +++ b/app/code/Magento/Bundle/view/base/templates/product/price/final_price.phtml @@ -1,6 +1,6 @@ getTierPriceList(); ' . $tierPriceModel->getSavePercent($price['price']) . '%' + '' . round($price['percentage_value']) . '%' ); ?>
  • diff --git a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js index 1a76acf174756..1be9ccb6ae320 100644 --- a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js +++ b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -295,6 +295,10 @@ define([ case 'hidden': optionHash = 'bundle-option-' + optionName + '##' + optionValue; optionQty = optionConfig[optionValue].qty || 0; + canQtyCustomize = optionConfig[optionValue].customQty === '1'; + qtyField = element.data('qtyField'); + qtyField.data('option', element); + toggleQtyField(qtyField, optionQty, optionId, optionValue, canQtyCustomize); tempChanges = utils.deepClone(optionConfig[optionValue].prices); tempChanges = applyTierPrice(tempChanges, optionQty, optionConfig); tempChanges = applyQty(tempChanges, optionQty); diff --git a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml index 5ab962f0b91b5..2c66156cbc7a1 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_simple.xml b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_simple.xml index e31437ec63963..fedd29f952b02 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_simple.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_simple.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_configure_type_bundle.xml b/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_configure_type_bundle.xml index e7128e45ddc7b..adb1b2911983b 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_configure_type_bundle.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_configure_type_bundle.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml index c5d613183e640..9abf0a4018980 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml index 09a27341fd5da..ddede2340995b 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/default.xml b/app/code/Magento/Bundle/view/frontend/layout/default.xml index a54d4b652b685..cb14616af5980 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/default.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml index 4db5f73f55bc5..991011db9fa08 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml index 1dba5769c0207..0e32c9fd9e816 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml index 6e1b90abf4d4e..927214fbcc174 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml index 7846245018a74..7463caa738083 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml index 7896e92bd34f4..c94b4957d267b 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml index 850e546a93a5a..d07959385bd9f 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml index 317b142514b9d..fb26de5bc2fdd 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml index dc5fb238dfd77..8c328c87a5c65 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml index 450f18d863ab5..57e39795df7da 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml index c4741ad6119f5..510168ac55e8a 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml index e3c91f1da5c20..f46b6260f3bd8 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml index ce42a5466cf06..536953423a3f2 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Bundle/view/frontend/requirejs-config.js b/app/code/Magento/Bundle/view/frontend/requirejs-config.js index 9dd12524124a6..51ab4cab6bb2c 100644 --- a/app/code/Magento/Bundle/view/frontend/requirejs-config.js +++ b/app/code/Magento/Bundle/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -12,4 +12,4 @@ var config = { productSummary: 'Magento_Bundle/js/product-summary' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/backbutton.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/backbutton.phtml index ddb483cf0220d..86cd52b6dc6fd 100644 --- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/backbutton.phtml +++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/backbutton.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/customize.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/customize.phtml index e72be96db1ab0..e3538ebd6caea 100644 --- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/customize.phtml +++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/customize.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/summary.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/summary.phtml index cb1de4e05e8a4..0fc7e6f9c8f06 100644 --- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/summary.phtml +++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/summary.phtml @@ -1,6 +1,6 @@ getId() ?> checkbox product bundle option change-container-classname" id="bundle-option-getId() ?>-getSelectionId() ?>" type="checkbox" - getRequired()) echo 'data-validate="{\'validate-one-required-by-name\':\'input[name^="bundle_option[' . $_option->getId() . ']"]:checked\'}"'?> + getRequired()) /* @escapeNotVerified */ echo 'data-validate="{\'validate-one-required-by-name\':\'input[name^="bundle_option[' . $_option->getId() . ']"]:checked\'}"'?> name="bundle_option[getId() ?>][getId() ?>]" data-selector="bundle_option[getId() ?>][getId() ?>]" isSelected($_selection)) echo ' checked="checked"' ?> diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/multi.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/multi.phtml index 5341055edff65..f408977ebb471 100644 --- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/multi.phtml +++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/multi.phtml @@ -1,6 +1,6 @@ parseAdditionalAttributes($dataRow['additional_attributes']); $dataRow['additional_attributes'] = $this->getNotBundleAttributes($additionalAttributes); } @@ -349,17 +346,38 @@ protected function cleanNotBundleAdditionalAttributes($dataRow) */ protected function getNotBundleAttributes($additionalAttributes) { - $cleanedAdditionalAttributes = ''; - foreach ($additionalAttributes as $attribute) { - list($attributeCode, $attributeValue) = explode(ImportProductModel::PAIR_NAME_VALUE_SEPARATOR, $attribute); - if (!in_array('bundle_' . $attributeCode, $this->getBundleColumns())) { - $cleanedAdditionalAttributes .= $attributeCode - . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR - . $attributeValue - . ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; + $filteredAttributes = []; + foreach ($additionalAttributes as $code => $value) { + if (!in_array('bundle_' . $code, $this->getBundleColumns())) { + $filteredAttributes[] = $code . ImportProductModel::PAIR_NAME_VALUE_SEPARATOR . $value; } } + return implode(ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $filteredAttributes); + } - return rtrim($cleanedAdditionalAttributes, ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR); + /** + * Retrieves additional attributes as array code=>value. + * + * @param string $additionalAttributes + * @return array + */ + private function parseAdditionalAttributes($additionalAttributes) + { + $attributeNameValuePairs = explode(ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $additionalAttributes); + $preparedAttributes = []; + $code = ''; + foreach ($attributeNameValuePairs as $attributeData) { + //process case when attribute has ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR inside its value + if (strpos($attributeData, ImportProductModel::PAIR_NAME_VALUE_SEPARATOR) === false) { + if (!$code) { + continue; + } + $preparedAttributes[$code] .= ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR . $attributeData; + continue; + } + list($code, $value) = explode(ImportProductModel::PAIR_NAME_VALUE_SEPARATOR, $attributeData, 2); + $preparedAttributes[$code] = $value; + } + return $preparedAttributes; } } diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php index 2d0f1264b6b8a..d5548f61c2bf2 100644 --- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php +++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php @@ -3,13 +3,12 @@ /** * Import entity of bundle product type * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\BundleImportExport\Model\Import\Product\Type; use \Magento\Bundle\Model\Product\Price as BundlePrice; -use \Magento\BundleImportExport\Model\Export\RowCustomizer; use \Magento\Catalog\Model\Product\Type\AbstractType; /** @@ -55,20 +54,6 @@ class Bundle extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abst */ const SELECTION_PRICE_TYPE_PERCENT = 1; - /** - * Instance of database adapter. - * - * @var \Magento\Framework\DB\Adapter\AdapterInterface - */ - protected $connection; - - /** - * Instance of application resource. - * - * @var \Magento\Framework\App\ResourceConnection - */ - protected $_resource; - /** * Array of cached options. * @@ -144,23 +129,6 @@ class Bundle extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abst 'multiselect' => 'multi', ]; - /** - * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory $attrSetColFac - * @param \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttrColFac - * @param \Magento\Framework\App\ResourceConnection $resource - * @param array $params - */ - public function __construct( - \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory $attrSetColFac, - \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $prodAttrColFac, - \Magento\Framework\App\ResourceConnection $resource, - array $params - ) { - parent::__construct($attrSetColFac, $prodAttrColFac, $resource, $params); - $this->_resource = $resource; - $this->connection = $resource->getConnection(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION); - } - /** * Parse selections. * diff --git a/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php b/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php index e7c313c56034b..0e67a2bc737c9 100644 --- a/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php +++ b/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php @@ -1,6 +1,6 @@ rowCustomizerMock->prepareData($this->productResourceCollection, [1]); - $attributes = 'attribute=1,sku_type=1,price_type=1,price_view=1,weight_type=1,values=values,shipment_type=1'; + $attributes = 'attribute=1,sku_type=1,attribute2="Text",price_type=1,price_view=1,weight_type=1,' + . 'values=values,shipment_type=1,attribute3=One,Two,Three'; $dataRow = [ 'sku' => 'sku1', 'additional_attributes' => $attributes @@ -186,7 +187,7 @@ public function testAddData() $preparedRow = $preparedData->addData($dataRow, 1); $expected = [ 'sku' => 'sku1', - 'additional_attributes' => 'attribute=1', + 'additional_attributes' => 'attribute=1,attribute2="Text",attribute3=One,Two,Three', 'bundle_price_type' => 'fixed', 'bundle_shipment_type' => 'separately', 'bundle_sku_type' => 'fixed', diff --git a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php index 2379ad7f10701..fd25dc247c341 100644 --- a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php +++ b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/BundleImportExport/etc/export.xml b/app/code/Magento/BundleImportExport/etc/export.xml index 04312d79f0260..c7fd951bfab53 100644 --- a/app/code/Magento/BundleImportExport/etc/export.xml +++ b/app/code/Magento/BundleImportExport/etc/export.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/BundleImportExport/etc/import.xml b/app/code/Magento/BundleImportExport/etc/import.xml index 2c23489002b1f..8daa5296a8c39 100644 --- a/app/code/Magento/BundleImportExport/etc/import.xml +++ b/app/code/Magento/BundleImportExport/etc/import.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/BundleImportExport/etc/module.xml b/app/code/Magento/BundleImportExport/etc/module.xml index d042b3bc7eb79..64f2c06b3c770 100644 --- a/app/code/Magento/BundleImportExport/etc/module.xml +++ b/app/code/Magento/BundleImportExport/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/BundleImportExport/registration.php b/app/code/Magento/BundleImportExport/registration.php index b417e7d20b79e..b4f80e749f130 100644 --- a/app/code/Magento/BundleImportExport/registration.php +++ b/app/code/Magento/BundleImportExport/registration.php @@ -1,6 +1,6 @@ getEvent()->getObject(); + if (!is_object($object)) { + return; + } if ($this->config->getType() == \Magento\PageCache\Model\Config::VARNISH && $this->config->isEnabled()) { - $object = $observer->getEvent()->getObject(); - if ($object instanceof \Magento\Framework\DataObject\IdentityInterface) { - $tags = []; - $pattern = "((^|,)%s(,|$))"; - foreach ($object->getIdentities() as $tag) { - $tags[] = sprintf($pattern, $tag); - } - if (!empty($tags)) { - $this->purgeCache->sendPurgeRequest(implode('|', array_unique($tags))); - } + $bareTags = $this->getTagResolver()->getTags($object); + + $tags = []; + $pattern = "((^|,)%s(,|$))"; + foreach ($bareTags as $tag) { + $tags[] = sprintf($pattern, $tag); + } + if (!empty($tags)) { + $this->purgeCache->sendPurgeRequest(implode('|', array_unique($tags))); } + + } + } + + /** + * @deprecated + * @return \Magento\Framework\App\Cache\Tag\Resolver + */ + private function getTagResolver() + { + if ($this->tagResolver === null) { + $this->tagResolver = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\App\Cache\Tag\Resolver::class); } + return $this->tagResolver; } } diff --git a/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php b/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php index 3cb6d8a054eb1..d4728fac0a17c 100644 --- a/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php +++ b/app/code/Magento/CacheInvalidate/Test/Unit/Model/PurgeCacheTest.php @@ -1,6 +1,6 @@ configMock = $this->getMock( \Magento\PageCache\Model\Config::class, ['getType', 'isEnabled'], @@ -39,6 +46,10 @@ protected function setUp() $this->configMock, $this->purgeCache ); + + $this->tagResolver = $this->getMock(\Magento\Framework\App\Cache\Tag\Resolver::class, [], [], '', false); + $helper->setBackwardCompatibleProperty($this->model, 'tagResolver', $this->tagResolver); + $this->observerMock = $this->getMock( \Magento\Framework\Event\Observer::class, ['getEvent'], @@ -65,10 +76,12 @@ public function testInvalidateVarnish() )->will( $this->returnValue(\Magento\PageCache\Model\Config::VARNISH) ); + $eventMock = $this->getMock(\Magento\Framework\Event::class, ['getObject'], [], '', false); $eventMock->expects($this->once())->method('getObject')->will($this->returnValue($this->observerObject)); $this->observerMock->expects($this->once())->method('getEvent')->will($this->returnValue($eventMock)); - $this->observerObject->expects($this->once())->method('getIdentities')->will($this->returnValue($tags)); + $this->tagResolver->expects($this->once())->method('getTags')->with($this->observerObject) + ->will($this->returnValue($tags)); $this->purgeCache->expects($this->once())->method('sendPurgeRequest')->with($pattern); $this->model->execute($this->observerMock); diff --git a/app/code/Magento/CacheInvalidate/composer.json b/app/code/Magento/CacheInvalidate/composer.json index cafccadb41ad8..c886e069b66e3 100644 --- a/app/code/Magento/CacheInvalidate/composer.json +++ b/app/code/Magento/CacheInvalidate/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-cache-invalidate", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/module-page-cache": "100.2.*", "magento/framework": "100.2.*" }, diff --git a/app/code/Magento/CacheInvalidate/etc/events.xml b/app/code/Magento/CacheInvalidate/etc/events.xml index 58ddeb64c9257..6103e661de55c 100644 --- a/app/code/Magento/CacheInvalidate/etc/events.xml +++ b/app/code/Magento/CacheInvalidate/etc/events.xml @@ -1,7 +1,7 @@ @@ -51,4 +51,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/CacheInvalidate/etc/module.xml b/app/code/Magento/CacheInvalidate/etc/module.xml index 7cc9d59df5959..b3277477fb62d 100644 --- a/app/code/Magento/CacheInvalidate/etc/module.xml +++ b/app/code/Magento/CacheInvalidate/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/CacheInvalidate/registration.php b/app/code/Magento/CacheInvalidate/registration.php index 21f5baf8f333c..00ddee3f6776b 100644 --- a/app/code/Magento/CacheInvalidate/registration.php +++ b/app/code/Magento/CacheInvalidate/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Captcha/etc/adminhtml/events.xml b/app/code/Magento/Captcha/etc/adminhtml/events.xml index 984e5e9e29f4e..7fcadbfd8f2ff 100644 --- a/app/code/Magento/Captcha/etc/adminhtml/events.xml +++ b/app/code/Magento/Captcha/etc/adminhtml/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/adminhtml/routes.xml b/app/code/Magento/Captcha/etc/adminhtml/routes.xml index e06b87beef772..6b6b6717c489a 100644 --- a/app/code/Magento/Captcha/etc/adminhtml/routes.xml +++ b/app/code/Magento/Captcha/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/adminhtml/system.xml b/app/code/Magento/Captcha/etc/adminhtml/system.xml index dc4c737597cce..88f0ae27f91c7 100644 --- a/app/code/Magento/Captcha/etc/adminhtml/system.xml +++ b/app/code/Magento/Captcha/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/config.xml b/app/code/Magento/Captcha/etc/config.xml index a068485910a77..d969626d73144 100644 --- a/app/code/Magento/Captcha/etc/config.xml +++ b/app/code/Magento/Captcha/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/crontab.xml b/app/code/Magento/Captcha/etc/crontab.xml index 846a15cbdbec6..d3d6e30e1a03a 100644 --- a/app/code/Magento/Captcha/etc/crontab.xml +++ b/app/code/Magento/Captcha/etc/crontab.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/crontab/di.xml b/app/code/Magento/Captcha/etc/crontab/di.xml index fd57ded2fb92b..f3086b469842b 100644 --- a/app/code/Magento/Captcha/etc/crontab/di.xml +++ b/app/code/Magento/Captcha/etc/crontab/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/di.xml b/app/code/Magento/Captcha/etc/di.xml index 0bb7660f27a6b..db624420ba647 100644 --- a/app/code/Magento/Captcha/etc/di.xml +++ b/app/code/Magento/Captcha/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/events.xml b/app/code/Magento/Captcha/etc/events.xml index 274058ec98e82..4223c4a2a3256 100644 --- a/app/code/Magento/Captcha/etc/events.xml +++ b/app/code/Magento/Captcha/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/frontend/di.xml b/app/code/Magento/Captcha/etc/frontend/di.xml index d15f8d5914998..209f9beb71a04 100644 --- a/app/code/Magento/Captcha/etc/frontend/di.xml +++ b/app/code/Magento/Captcha/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/frontend/events.xml b/app/code/Magento/Captcha/etc/frontend/events.xml index e1441f0311ee8..dfa0d1b428557 100644 --- a/app/code/Magento/Captcha/etc/frontend/events.xml +++ b/app/code/Magento/Captcha/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/etc/frontend/routes.xml b/app/code/Magento/Captcha/etc/frontend/routes.xml index 255f4551daf5d..d4bbe64821a91 100644 --- a/app/code/Magento/Captcha/etc/frontend/routes.xml +++ b/app/code/Magento/Captcha/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Captcha/etc/module.xml b/app/code/Magento/Captcha/etc/module.xml index 1703142e54133..698604928afb6 100644 --- a/app/code/Magento/Captcha/etc/module.xml +++ b/app/code/Magento/Captcha/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/registration.php b/app/code/Magento/Captcha/registration.php index a8fce947e6697..488ac412a8926 100644 --- a/app/code/Magento/Captcha/registration.php +++ b/app/code/Magento/Captcha/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Captcha/view/adminhtml/layout/adminhtml_auth_login.xml b/app/code/Magento/Captcha/view/adminhtml/layout/adminhtml_auth_login.xml index 3cb5ffbbf5ae3..8c093257f1790 100644 --- a/app/code/Magento/Captcha/view/adminhtml/layout/adminhtml_auth_login.xml +++ b/app/code/Magento/Captcha/view/adminhtml/layout/adminhtml_auth_login.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/adminhtml/templates/default.phtml b/app/code/Magento/Captcha/view/adminhtml/templates/default.phtml index 1aceb9ff95d3a..37d2ed6fe1238 100644 --- a/app/code/Magento/Captcha/view/adminhtml/templates/default.phtml +++ b/app/code/Magento/Captcha/view/adminhtml/templates/default.phtml @@ -1,18 +1,19 @@ getCaptchaModel(); ?> - - -getCaptchaModel() ?>
    isCaseSensitive()) :?>
    - Attention: Captcha is case sensitive.') ?> + escapeHtml(__('Attention: Captcha is case sensitive.'), ['strong']) ?>
    @@ -33,7 +34,7 @@ id="captcha-reload" class="captcha-reload" src="escapeUrl($block->getViewFileUrl('Magento_Captcha::reload.png')) ?>" - alt=""/> + alt="escapeHtmlAttr(__('Reload captcha')) ?>"/> escapeUrl($block->getRefreshUrl()) ?>', 'escapeJs($block->getFormId()) ?>'); + var captcha = new Captcha('escapeJs($block->escapeUrl($block->getRefreshUrl())) ?>', 'escapeJs($block->escapeHtml($block->getFormId())) ?>'); $('captcha-reload').observe('click', function () { captcha.refresh(this); diff --git a/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml index 9213f0db67192..b4fc252bb4a7b 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/checkout_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/frontend/layout/contact_index_index.xml b/app/code/Magento/Captcha/view/frontend/layout/contact_index_index.xml index 9e31eea8aaeba..1460d8fac6974 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/contact_index_index.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/contact_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/frontend/layout/customer_account_create.xml b/app/code/Magento/Captcha/view/frontend/layout/customer_account_create.xml index 573af66d5bd31..cd72cc5857b83 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/customer_account_create.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/customer_account_create.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/frontend/layout/customer_account_edit.xml b/app/code/Magento/Captcha/view/frontend/layout/customer_account_edit.xml index 875479c49954c..9700e88006f10 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/customer_account_edit.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/customer_account_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/frontend/layout/customer_account_forgotpassword.xml b/app/code/Magento/Captcha/view/frontend/layout/customer_account_forgotpassword.xml index dc92c7c3548bc..1f25fa040b591 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/customer_account_forgotpassword.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/customer_account_forgotpassword.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/frontend/layout/customer_account_login.xml b/app/code/Magento/Captcha/view/frontend/layout/customer_account_login.xml index bcabf0adccc26..3a24e44fd1afe 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/customer_account_login.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/customer_account_login.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/frontend/layout/default.xml b/app/code/Magento/Captcha/view/frontend/layout/default.xml index 9d6a234514855..43a770c54c0ca 100644 --- a/app/code/Magento/Captcha/view/frontend/layout/default.xml +++ b/app/code/Magento/Captcha/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Captcha/view/frontend/requirejs-config.js b/app/code/Magento/Captcha/view/frontend/requirejs-config.js index 72f7d627b8707..ff1d9f1acc7b1 100644 --- a/app/code/Magento/Captcha/view/frontend/requirejs-config.js +++ b/app/code/Magento/Captcha/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -9,4 +9,4 @@ var config = { captcha: 'Magento_Captcha/captcha' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Captcha/view/frontend/templates/default.phtml b/app/code/Magento/Captcha/view/frontend/templates/default.phtml index 4046b5f96ecea..e028ea19fa8b4 100644 --- a/app/code/Magento/Captcha/view/frontend/templates/default.phtml +++ b/app/code/Magento/Captcha/view/frontend/templates/default.phtml @@ -1,17 +1,18 @@ getCaptchaModel(); ?> - - -getCaptchaModel() ?>
    - +
    @@ -22,13 +23,13 @@ "imageLoader": "escapeUrl($block->getViewFileUrl('images/loader-2.gif')) ?>", "type": "escapeHtmlAttr($block->getFormId()) ?>"}}'>
    - <?php /* @escapeNotVerified */ echo __('Please type the letters below')?> - + <?php echo $block->escapeHtmlAttr(__('Please type the letters below')) ?> +
    isCaseSensitive()) :?>
    - Attention: Captcha is case sensitive.') ?> + escapeHtml(__('Attention: Captcha is case sensitive.'), ['strong']) ?>
    diff --git a/app/code/Magento/Captcha/view/frontend/templates/js/components.phtml b/app/code/Magento/Captcha/view/frontend/templates/js/components.phtml index e490a6aa04923..bdcb2e9bf7747 100644 --- a/app/code/Magento/Captcha/view/frontend/templates/js/components.phtml +++ b/app/code/Magento/Captcha/view/frontend/templates/js/components.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/Api/AttributeSetFinderInterface.php b/app/code/Magento/Catalog/Api/AttributeSetFinderInterface.php index 4dabce697b30f..c7df36623ff83 100644 --- a/app/code/Magento/Catalog/Api/AttributeSetFinderInterface.php +++ b/app/code/Magento/Catalog/Api/AttributeSetFinderInterface.php @@ -1,7 +1,7 @@ (int) Entity identified or entity link field. + * 'value' => (float) Special price value. + * 'store_id' => (int) Store Id. + * 'sku' => (string) Product SKU. + * 'price_from' => (string) Special price from date value in UTC. + * 'price_to' => (string) Special price to date value in UTC. + * ] + */ + public function get(array $skus); + + /** + * Update product special prices. + * + * @param array $prices + * $prices = [ + * 'entity_id' => (int) Entity identified or entity link field. Required. + * 'attribute_id' => (int) Special price attribute Id. Required. + * 'store_id' => (int) Store Id. Required. + * 'value' => (float) Special price value. Required. + * 'price_from' => (string) Special price from date value in Y-m-d H:i:s format in UTC. Optional. + * 'price_to' => (string) Special price to date value in Y-m-d H:i:s format in UTC. Optional. + * ]; + * @return bool + * @throws \Magento\Framework\Exception\CouldNotSaveException Thrown if error occurred during price save. + */ + public function update(array $prices); + + /** + * Delete product special prices. + * + * @param array $prices + * $prices = [ + * 'entity_id' => (int) Entity identified or entity link field. Required. + * 'attribute_id' => (int) Special price attribute Id. Required. + * 'store_id' => (int) Store Id. Required. + * 'value' => (float) Special price value. Required. + * 'price_from' => (string) Special price from date value in Y-m-d H:i:s format in UTC. Optional. + * 'price_to' => (string) Special price to date value in Y-m-d H:i:s format in UTC. Optional. + * ]; + * @return bool + * @throws \Magento\Framework\Exception\CouldNotDeleteException Thrown if error occurred during price delete. + */ + public function delete(array $prices); +} diff --git a/app/code/Magento/Catalog/Api/SpecialPriceStorageInterface.php b/app/code/Magento/Catalog/Api/SpecialPriceStorageInterface.php new file mode 100644 index 0000000000000..fe234ab675b3f --- /dev/null +++ b/app/code/Magento/Catalog/Api/SpecialPriceStorageInterface.php @@ -0,0 +1,49 @@ +stat($this->_mediaConfig->getMediaPath($image['file'])); $image['size'] = $fileHandler['size']; } catch (FileSystemException $e) { - $staticDir = $this->_filesystem->getDirectoryRead(DirectoryList::STATIC_VIEW); - $image['url'] = $this->getImageHelper()->getDefaultPlaceholderUrl('thumbnail'); - $fileHandler = $staticDir->stat( - $this->getAssetRepo() - ->createAsset($this->getImageHelper()->getPlaceholder('thumbnail'))->getPath() - ); - $image['size'] = $fileHandler['size']; + $image['url'] = $this->getImageHelper()->getDefaultPlaceholderUrl('small_image'); + $image['size'] = 0; $this->_logger->warning($e); } } @@ -262,18 +252,4 @@ private function getImageHelper() } return $this->imageHelper; } - - /** - * @return \Magento\Framework\View\Asset\Repository - * @deprecated - */ - private function getAssetRepo() - { - if ($this->assetRepo === null) { - $this->assetRepo = \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\View\Asset\Repository::class); - } - - return $this->assetRepo; - } } diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Image.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Image.php index 8fc1e26f0cb7f..03ccd4135355c 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Image.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Image.php @@ -1,6 +1,6 @@ getTypeInstance()->hasRequiredOptions($product)) { + if (!$product->getTypeInstance()->isPossibleBuyFromList($product)) { if (!isset($additional['_escape'])) { $additional['_escape'] = true; } diff --git a/app/code/Magento/Catalog/Block/Product/AwareInterface.php b/app/code/Magento/Catalog/Block/Product/AwareInterface.php index de9564075531c..deec15b976ba3 100644 --- a/app/code/Magento/Catalog/Block/Product/AwareInterface.php +++ b/app/code/Magento/Catalog/Block/Product/AwareInterface.php @@ -1,6 +1,6 @@ $product->getId(), 'priceFormat' => $this->_localeFormat->getPriceFormat() - ]; + ]; return $this->_jsonEncoder->encode($config); } $tierPrices = []; $tierPricesList = $product->getPriceInfo()->getPrice('tier_price')->getTierPriceList(); foreach ($tierPricesList as $tierPrice) { - $tierPrices[] = $this->priceCurrency->convert($tierPrice['price']->getValue()); + $tierPrices[] = $tierPrice['price']->getValue(); } $config = [ - 'productId' => $product->getId(), + 'productId' => $product->getId(), 'priceFormat' => $this->_localeFormat->getPriceFormat(), - 'prices' => [ - 'oldPrice' => [ - 'amount' => $this->priceCurrency->convert( - $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue() - ), + 'prices' => [ + 'oldPrice' => [ + 'amount' => $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue(), 'adjustments' => [] ], - 'basePrice' => [ - 'amount' => $this->priceCurrency->convert( - $product->getPriceInfo()->getPrice('final_price')->getAmount()->getBaseAmount() - ), + 'basePrice' => [ + 'amount' => $product->getPriceInfo()->getPrice('final_price')->getAmount()->getBaseAmount(), 'adjustments' => [] ], 'finalPrice' => [ - 'amount' => $this->priceCurrency->convert( - $product->getPriceInfo()->getPrice('final_price')->getAmount()->getValue() - ), + 'amount' => $product->getPriceInfo()->getPrice('final_price')->getAmount()->getValue(), 'adjustments' => [] ] ], - 'idSuffix' => '_clone', - 'tierPrices' => $tierPrices + 'idSuffix' => '_clone', + 'tierPrices' => $tierPrices ]; $responseObject = new \Magento\Framework\DataObject(); diff --git a/app/code/Magento/Catalog/Block/Product/View/AbstractView.php b/app/code/Magento/Catalog/Block/Product/View/AbstractView.php index c8cc393c66006..5daaff14ed733 100644 --- a/app/code/Magento/Catalog/Block/Product/View/AbstractView.php +++ b/app/code/Magento/Catalog/Block/Product/View/AbstractView.php @@ -1,6 +1,6 @@ setData( 'medium_image_url', - $this->_imageHelper->init($product, 'product_page_image_medium') - ->constrainOnly(true)->keepAspectRatio(true)->keepFrame(false) + $this->_imageHelper->init($product, 'product_page_image_medium_no_frame') ->setImageFile($image->getFile()) ->getUrl() ); $image->setData( 'large_image_url', - $this->_imageHelper->init($product, 'product_page_image_large') - ->constrainOnly(true)->keepAspectRatio(true)->keepFrame(false) + $this->_imageHelper->init($product, 'product_page_image_large_no_frame') ->setImageFile($image->getFile()) ->getUrl() ); diff --git a/app/code/Magento/Catalog/Block/Product/View/Options.php b/app/code/Magento/Catalog/Block/Product/View/Options.php index 349352513bec6..5f045fdacfc3f 100644 --- a/app/code/Magento/Catalog/Block/Product/View/Options.php +++ b/app/code/Magento/Catalog/Block/Product/View/Options.php @@ -1,6 +1,6 @@ appState = $appState; $this->productCollectionFactory = $productCollectionFactory; @@ -69,11 +58,13 @@ protected function configure() /** * {@inheritdoc} */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $this->appState->setAreaCode('catalog'); + protected function execute( + \Symfony\Component\Console\Input\InputInterface $input, + \Symfony\Component\Console\Output\OutputInterface $output + ) { + $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL); - /** @var ProductCollection $productCollection */ + /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection */ $productCollection = $this->productCollectionFactory->create(); $productIds = $productCollection->getAllIds(); if (!count($productIds)) { @@ -85,13 +76,13 @@ protected function execute(InputInterface $input, OutputInterface $output) try { foreach ($productIds as $productId) { try { - /** @var Product $product */ + /** @var \Magento\Catalog\Model\Product $product */ $product = $this->productRepository->getById($productId); - } catch (NoSuchEntityException $e) { + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { continue; } - /** @var ImageCache $imageCache */ + /** @var \Magento\Catalog\Model\Product\Image\Cache $imageCache */ $imageCache = $this->imageCacheFactory->create(); $imageCache->generate($product); diff --git a/app/code/Magento/Catalog/Console/Command/ProductAttributesCleanUp.php b/app/code/Magento/Catalog/Console/Command/ProductAttributesCleanUp.php index d1b938296f9bd..2a20566a8e03d 100644 --- a/app/code/Magento/Catalog/Console/Command/ProductAttributesCleanUp.php +++ b/app/code/Magento/Catalog/Console/Command/ProductAttributesCleanUp.php @@ -1,6 +1,6 @@ setDecorated(true); - $this->appState->setAreaCode('catalog'); + $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL); $connection = $this->attributeResource->getConnection(); $attributeTables = $this->getAttributeTables(); @@ -101,11 +101,14 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln(""); $output->writeln("Unused product attributes successfully cleaned up:"); $output->writeln(" " . implode("\n ", $attributeTables) . ""); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } catch (\Exception $exception) { $this->attributeResource->rollBack(); $output->writeln(""); $output->writeln("{$exception->getMessage()}"); + // we must have an exit code higher than zero to indicate something was wrong + return \Magento\Framework\Console\Cli::RETURN_FAILURE; } } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php index 8f8f21e207bf5..6c42a7b28704f 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php @@ -1,6 +1,6 @@ getRequest()->getParam('id', false); + $categoryId = $this->resolveCategoryId(); $storeId = (int)$this->getRequest()->getParam('store'); $category = $this->_objectManager->create(\Magento\Catalog\Model\Category::class); $category->setStoreId($storeId); @@ -62,6 +62,18 @@ protected function _initCategory($getRootInstead = false) return $category; } + /** + * Resolve Category Id (from get or from post) + * + * @return int + */ + private function resolveCategoryId() + { + $categoryId = (int)$this->getRequest()->getParam('id', false); + + return $categoryId ?: (int)$this->getRequest()->getParam('entity_id', false); + } + /** * Build response for ajax request * diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php index 663bf6a5b0915..29ffcdf1682f8 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Add.php @@ -1,7 +1,7 @@ ajaxRequestResponse($category, $resultPage); } + $resultPageTitle = $categoryId ? $category->getName() . ' (ID: ' . $categoryId . ')' : __('Categories'); $resultPage->setActiveMenu('Magento_Catalog::catalog_categories'); $resultPage->getConfig()->getTitle()->prepend(__('Categories')); - $resultPage->getConfig()->getTitle()->prepend($categoryId ? $category->getName() : __('Categories')); + $resultPage->getConfig()->getTitle()->prepend($resultPageTitle); $resultPage->addBreadcrumb(__('Manage Catalog Categories'), __('Manage Categories')); $block = $resultPage->getLayout()->getBlock('catalog.wysiwyg.js'); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Grid.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Grid.php index 4b2fa125ac137..0eef32b191abc 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Grid.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Grid.php @@ -1,7 +1,7 @@ _request->getParam('param_name', 'image'); + try { - $result = $this->imageUploader->saveFileToTmpDir('image'); + $result = $this->imageUploader->saveFileToTmpDir($imageId); $result['cookie'] = [ 'name' => $this->_getSession()->getName(), diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php index 5640873acbd6b..7c02a5daa5d43 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php @@ -1,7 +1,7 @@ messageManager->addSuccess(__('You moved the category')); + $this->messageManager->addSuccess(__('You moved the category.')); } $block->setMessages($this->messageManager->getMessages(true)); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php index 4202d21089563..f8aa64e6bdc1e 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/RefreshPath.php @@ -1,7 +1,7 @@ resultRawFactory = $resultRawFactory; $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; $this->storeManager = $storeManager; + $this->eavConfig = $eavConfig + ?: \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class); } /** * Filter category data * + * @deprecated * @param array $rawData * @return array */ protected function _filterCategoryPostData(array $rawData) { $data = $rawData; - // @todo It is a workaround to prevent saving this data in category model and it has to be refactored in future if (isset($data['image']) && is_array($data['image'])) { if (!empty($data['image']['delete'])) { $data['image'] = null; @@ -126,7 +136,7 @@ public function execute() $this->storeManager->setCurrentStore($store->getCode()); $parentId = isset($categoryPostData['parent']) ? $categoryPostData['parent'] : null; if ($categoryPostData) { - $category->addData($this->_filterCategoryPostData($categoryPostData)); + $category->addData($categoryPostData); if ($isNewCategory) { $parentCategory = $this->getParentCategory($parentId, $storeId); $category->setPath($parentCategory->getPath()); @@ -248,18 +258,30 @@ public function execute() } /** - * Image data preprocessing + * Sets image attribute data to false if image was removed * * @param array $data - * * @return array */ public function imagePreprocessing($data) { - if (empty($data['image'])) { - unset($data['image']); - $data['image']['delete'] = true; + $entityType = $this->eavConfig->getEntityType(CategoryAttributeInterface::ENTITY_TYPE_CODE); + + foreach ($entityType->getAttributeCollection() as $attributeModel) { + $attributeCode = $attributeModel->getAttributeCode(); + $backendModel = $attributeModel->getBackend(); + + if (isset($data[$attributeCode])) { + continue; + } + + if (!$backendModel instanceof \Magento\Catalog\Model\Category\Attribute\Backend\Image) { + continue; + } + + $data[$attributeCode] = false; } + return $data; } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/SuggestCategories.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/SuggestCategories.php index 9ab7e84cead06..2e34cf244ef9a 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/SuggestCategories.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/SuggestCategories.php @@ -1,7 +1,7 @@ getSearchCriteriaBuilder() ->addFilter('attribute_set_id', $attributeSet->getAttributeSetId()) ->addFilter('attribute_group_code', $groupCode) - ->addSortOrder($this->getSortOrderBuilder()->setAscendingDirection()->create()) ->setPageSize(1) ->create(); @@ -252,18 +245,6 @@ private function getSearchCriteriaBuilder() return $this->searchCriteriaBuilder; } - /** - * @return SortOrderBuilder - */ - private function getSortOrderBuilder() - { - if (null === $this->sortOrderBuilder) { - $this->sortOrderBuilder = \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\Api\SortOrderBuilder::class); - } - return $this->sortOrderBuilder; - } - /** * @return AttributeManagementInterface */ diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGrid.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGrid.php index 7a0190d99db51..3b370edc27008 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGrid.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/AlertsPriceGrid.php @@ -1,7 +1,7 @@ $checkboxValue) { - if (!$checkboxValue) { - unset($productData['website_ids'][$websiteId]); - } - } + $productData['website_ids'] = $this->filterWebsiteIds($productData['website_ids']); $wasLockedMedia = false; if ($product->isLockedAttribute('media')) { @@ -199,6 +194,9 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra $customOptions = []; foreach ($options as $customOptionData) { if (empty($customOptionData['is_delete'])) { + if (empty($customOptionData['option_id'])) { + $customOptionData['option_id'] = null; + } if (isset($customOptionData['values'])) { $customOptionData['values'] = array_filter($customOptionData['values'], function ($valueData) { return empty($valueData['is_delete']); @@ -206,7 +204,6 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra } $customOption = $this->getCustomOptionFactory()->create(['data' => $customOptionData]); $customOption->setProductSku($product->getSku()); - $customOption->setOptionId(null); $customOptions[] = $customOption; } } @@ -255,7 +252,7 @@ protected function setProductLinks(\Magento\Catalog\Model\Product $product) foreach ($linkTypes as $linkType => $readonly) { if (isset($links[$linkType]) && !$readonly) { - foreach ((array) $links[$linkType] as $linkData) { + foreach ((array)$links[$linkType] as $linkData) { if (empty($linkData['id'])) { continue; } @@ -321,9 +318,11 @@ public function mergeProductOptions($productOptions, $overwriteOptions) if (isset($option['values']) && isset($overwriteOptions[$optionId]['values'])) { foreach ($option['values'] as $valueIndex => $value) { - $valueId = $value['option_type_id']; - $value = $this->overwriteValue($valueId, $value, $overwriteOptions[$optionId]['values']); - $option['values'][$valueIndex] = $value; + if (isset($value['option_type_id'])) { + $valueId = $value['option_type_id']; + $value = $this->overwriteValue($valueId, $value, $overwriteOptions[$optionId]['values']); + $option['values'][$valueIndex] = $value; + } } } @@ -347,6 +346,9 @@ private function overwriteValue($optionId, $option, $overwriteOptions) foreach ($overwriteOptions[$optionId] as $fieldName => $overwrite) { if ($overwrite && isset($option[$fieldName]) && isset($option['default_' . $fieldName])) { $option[$fieldName] = $option['default_' . $fieldName]; + if ('title' == $fieldName) { + $option['is_delete_store_title'] = 1; + } } } } @@ -415,4 +417,23 @@ private function getDateTimeFilter() } return $this->dateTimeFilter; } + + /** + * Remove ids of non selected websites from $websiteIds array and return filtered data + * $websiteIds parameter expects array with website ids as keys and 1 (selected) or 0 (non selected) as values + * Only one id (default website ID) will be set to $websiteIds array when the single store mode is turned on + * + * @param array $websiteIds + * @return array + */ + private function filterWebsiteIds($websiteIds) + { + if (!$this->storeManager->isSingleStoreMode()) { + $websiteIds = array_filter((array)$websiteIds); + } else { + $websiteIds[$this->storeManager->getWebsite(true)->getId()] = 1; + } + + return $websiteIds; + } } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/HandlerFactory.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/HandlerFactory.php index f282df484b076..d720c26a8a905 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/HandlerFactory.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/HandlerFactory.php @@ -1,6 +1,6 @@ getAllIds(); $storeId = (int) $this->getRequest()->getParam('store', 0); $status = (int) $this->getRequest()->getParam('status'); + $filters = (array)$this->getRequest()->getParam('filters', []); + + if (isset($filters['store_id'])) { + $storeId = (int)$filters['store_id']; + } try { $this->_validateMassStatus($productIds, $status); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php index a5153a7342674..62fc127b43a3d 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php @@ -1,7 +1,7 @@ save(); $this->messageManager->addSuccess(__('You saved the attribute set.')); + } catch (\Magento\Framework\Exception\AlreadyExistsException $e) { + $this->messageManager->addErrorMessage($e->getMessage()); + $hasError = true; } catch (\Magento\Framework\Exception\LocalizedException $e) { $this->messageManager->addError($e->getMessage()); $hasError = true; diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/SetGrid.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/SetGrid.php index c0f7246f334f0..b9226a622f598 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/SetGrid.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Set/SetGrid.php @@ -1,7 +1,7 @@ addPageLayoutHandles(['type' => $parentType]); + $page->addPageLayoutHandles(['type' => $parentType], null, false); } - $page->addPageLayoutHandles(['type' => $type, 'id' => $category->getId()]); + $page->addPageLayoutHandles(['type' => $type], null, false); + $page->addPageLayoutHandles(['id' => $category->getId()]); // apply custom layout update once layout is loaded $layoutUpdates = $settings->getLayoutUpdates(); if ($layoutUpdates && is_array($layoutUpdates)) { foreach ($layoutUpdates as $layoutUpdate) { $page->addUpdate($layoutUpdate); - $page->addPageLayoutHandles(['layout_update' => md5($layoutUpdate)]); + $page->addPageLayoutHandles(['layout_update' => md5($layoutUpdate)], null, false); } } diff --git a/app/code/Magento/Catalog/Controller/Index/Index.php b/app/code/Magento/Catalog/Controller/Index/Index.php index 7512affdef3c9..4b83aee1a061e 100644 --- a/app/code/Magento/Catalog/Controller/Index/Index.php +++ b/app/code/Magento/Catalog/Controller/Index/Index.php @@ -1,6 +1,6 @@ resource = $resource; + $this->attributeRepository = $attributeRepository; + $this->scopeConfig = $scopeConfig; + } + + /** + * Delete all price values for non-admin stores if PRICE_SCOPE is global + * + * @return void + */ + public function execute() + { + $priceScope = $this->scopeConfig->getValue(Store::XML_PATH_PRICE_SCOPE); + if ($priceScope == Store::PRICE_SCOPE_GLOBAL) { + /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $priceAttribute */ + $priceAttribute = $this->attributeRepository + ->get(ProductAttributeInterface::ENTITY_TYPE_CODE, ProductAttributeInterface::CODE_PRICE); + $connection = $this->resource->getConnection(); + $conditions = [ + $connection->quoteInto('attribute_id = ?', $priceAttribute->getId()), + $connection->quoteInto('store_id != ?', Store::DEFAULT_STORE_ID), + ]; + + $connection->delete( + $priceAttribute->getBackend()->getTable(), + $conditions + ); + } + } +} diff --git a/app/code/Magento/Catalog/Cron/RefreshSpecialPrices.php b/app/code/Magento/Catalog/Cron/RefreshSpecialPrices.php index e3a63e0367328..5e04b026db3d4 100644 --- a/app/code/Magento/Catalog/Cron/RefreshSpecialPrices.php +++ b/app/code/Magento/Catalog/Cron/RefreshSpecialPrices.php @@ -1,6 +1,6 @@ _getModel()->setDestinationSubdir($this->getType()); - $this->_getModel()->setWidth($this->getWidth()); $this->_getModel()->setHeight($this->getHeight()); @@ -241,25 +240,25 @@ protected function setWatermarkProperties() { $this->setWatermark( $this->scopeConfig->getValue( - "design/watermark/{$this->_getModel()->getDestinationSubdir()}_image", + "design/watermark/{$this->getType()}_image", \Magento\Store\Model\ScopeInterface::SCOPE_STORE ) ); $this->setWatermarkImageOpacity( $this->scopeConfig->getValue( - "design/watermark/{$this->_getModel()->getDestinationSubdir()}_imageOpacity", + "design/watermark/{$this->getType()}_imageOpacity", \Magento\Store\Model\ScopeInterface::SCOPE_STORE ) ); $this->setWatermarkPosition( $this->scopeConfig->getValue( - "design/watermark/{$this->_getModel()->getDestinationSubdir()}_position", + "design/watermark/{$this->getType()}_position", \Magento\Store\Model\ScopeInterface::SCOPE_STORE ) ); $this->setWatermarkSize( $this->scopeConfig->getValue( - "design/watermark/{$this->_getModel()->getDestinationSubdir()}_size", + "design/watermark/{$this->getType()}_size", \Magento\Store\Model\ScopeInterface::SCOPE_STORE ) ); @@ -500,10 +499,7 @@ protected function initBaseFile() protected function isScheduledActionsAllowed() { $model = $this->_getModel(); - if ($model->isBaseFilePlaceholder() - && $model->getNewFile() === true - || $model->isCached() - ) { + if ($model->isBaseFilePlaceholder() || $model->isCached()) { return false; } return true; diff --git a/app/code/Magento/Catalog/Helper/Output.php b/app/code/Magento/Catalog/Helper/Output.php index 0b4b8a0dab9a6..a738b3fddfa07 100644 --- a/app/code/Magento/Catalog/Helper/Output.php +++ b/app/code/Magento/Catalog/Helper/Output.php @@ -1,6 +1,6 @@ getEncodedUrl($this->_getUrl('catalog/product_compare')); $data = [ - \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => $listCleanUrl, - 'product' => $product->getId() + \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => '', + 'product' => $product->getId(), + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove this item from your Compare Products list?') ]; return $this->postHelper->getPostData($this->getRemoveUrl(), $data); } @@ -253,9 +254,10 @@ public function getClearListUrl() */ public function getPostDataClearList() { - $refererUrl = $this->_getRequest()->getServer('HTTP_REFERER'); $params = [ - \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlEncoder->encode($refererUrl) + \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => '', + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove all items from your Compare Products list?'), ]; return $this->postHelper->getPostData($this->getClearListUrl(), $params); } diff --git a/app/code/Magento/Catalog/Helper/Product/Composite.php b/app/code/Magento/Catalog/Helper/Product/Composite.php index fcd710ad1ec84..5e519540c78ca 100644 --- a/app/code/Magento/Catalog/Helper/Product/Composite.php +++ b/app/code/Magento/Catalog/Helper/Product/Composite.php @@ -1,6 +1,6 @@ _productOptionFactory = $productOptionFactory; $this->filter = $filter; $this->string = $string; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); parent::__construct($context); } @@ -105,7 +115,7 @@ public function getCustomOptions(\Magento\Catalog\Model\Product\Configuration\It $addOptions = $item->getOptionByCode('additional_options'); if ($addOptions) { - $options = array_merge($options, unserialize($addOptions->getValue())); + $options = array_merge($options, $this->serializer->unserialize($addOptions->getValue())); } return $options; diff --git a/app/code/Magento/Catalog/Helper/Product/Configuration/ConfigurationInterface.php b/app/code/Magento/Catalog/Helper/Product/Configuration/ConfigurationInterface.php index 0e47bc998e4bb..26b4e9e180327 100644 --- a/app/code/Magento/Catalog/Helper/Product/Configuration/ConfigurationInterface.php +++ b/app/code/Magento/Catalog/Helper/Product/Configuration/ConfigurationInterface.php @@ -1,6 +1,6 @@ getBeforeHandles()) { foreach ($params->getBeforeHandles() as $handle) { - $resultPage->addPageLayoutHandles( - ['id' => $product->getId(), 'sku' => $urlSafeSku, 'type' => $product->getTypeId()], - $handle - ); + $resultPage->addPageLayoutHandles(['id' => $product->getId(), 'sku' => $urlSafeSku], $handle); + $resultPage->addPageLayoutHandles(['type' => $product->getTypeId()], $handle, false); } } - $resultPage->addPageLayoutHandles( - ['id' => $product->getId(), 'sku' => $urlSafeSku, 'type' => $product->getTypeId()] - ); + $resultPage->addPageLayoutHandles(['id' => $product->getId(), 'sku' => $urlSafeSku]); + $resultPage->addPageLayoutHandles(['type' => $product->getTypeId()], null, false); if ($params && $params->getAfterHandles()) { foreach ($params->getAfterHandles() as $handle) { - $resultPage->addPageLayoutHandles( - ['id' => $product->getId(), 'sku' => $urlSafeSku, 'type' => $product->getTypeId()], - $handle - ); + $resultPage->addPageLayoutHandles(['id' => $product->getId(), 'sku' => $urlSafeSku], $handle); + $resultPage->addPageLayoutHandles(['type' => $product->getTypeId()], $handle, false); } } diff --git a/app/code/Magento/Catalog/Model/AbstractModel.php b/app/code/Magento/Catalog/Model/AbstractModel.php index 40188c4efc9df..ccaa5829cd717 100644 --- a/app/code/Magento/Catalog/Model/AbstractModel.php +++ b/app/code/Magento/Catalog/Model/AbstractModel.php @@ -1,6 +1,6 @@ getImage(); + $image = $this->getData($attributeCode); if ($image) { if (is_string($image)) { $url = $this->_storeManager->getStore()->getBaseUrl( diff --git a/app/code/Magento/Catalog/Model/Category/Attribute.php b/app/code/Magento/Catalog/Model/Category/Attribute.php index 51c3b87937cf7..94a108c063f51 100644 --- a/app/code/Magento/Catalog/Model/Category/Attribute.php +++ b/app/code/Magento/Catalog/Model/Category/Attribute.php @@ -1,6 +1,6 @@ getAttribute()->getName(); + $value = $object->getData($attributeName); + + if ($imageName = $this->getUploadedImageName($value)) { + $object->setData($this->additionalData . $attributeName, $value); + $object->setData($attributeName, $imageName); + } else if (!is_string($value)) { + $object->setData($attributeName, ''); + } + + return parent::beforeSave($object); + } + + /** * @return \Magento\Catalog\Model\ImageUploader * * @deprecated @@ -79,10 +112,10 @@ public function __construct( private function getImageUploader() { if ($this->imageUploader === null) { - $this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()->get( - \Magento\Catalog\CategoryImageUpload::class - ); + $this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Catalog\CategoryImageUpload::class); } + return $this->imageUploader; } @@ -94,15 +127,16 @@ private function getImageUploader() */ public function afterSave($object) { - $image = $object->getData($this->getAttribute()->getName(), null); + $value = $object->getData($this->additionalData . $this->getAttribute()->getName()); - if ($image !== null) { + if ($imageName = $this->getUploadedImageName($value)) { try { - $this->getImageUploader()->moveFileFromTmp($image); + $this->getImageUploader()->moveFileFromTmp($imageName); } catch (\Exception $e) { $this->_logger->critical($e); } } + return $this; } } diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Sortby.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Sortby.php index 516ce756dff97..d18146ebae85e 100644 --- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Sortby.php +++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Sortby.php @@ -1,6 +1,6 @@ storeManager = $storeManager; $this->request = $request; $this->categoryFactory = $categoryFactory; + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); - $this->meta = $this->prepareMeta($this->meta); + } + + /** + * @inheritdoc + */ + public function getMeta() + { + $meta = parent::getMeta(); + $meta = $this->prepareMeta($meta); + + $category = $this->getCurrentCategory(); + + if ($category) { + $meta = $this->addUseDefaultValueCheckbox($category, $meta); + $meta = $this->resolveParentInheritance($category, $meta); + } + + return $meta; + } + + /** + * @param Category $category + * @param array $meta + * @return array + */ + private function addUseDefaultValueCheckbox(Category $category, array $meta) + { + /** @var EavAttributeInterface $attribute */ + foreach ($category->getAttributes() as $attribute) { + $attributeCode = $attribute->getAttributeCode(); + $canDisplayUseDefault = $attribute->getScope() != EavAttributeInterface::SCOPE_GLOBAL_TEXT + && $category->getId() + && $category->getStoreId(); + $attributePath = $this->getArrayManager()->findPath($attributeCode, $meta); + + if ( + !$attributePath + || !$canDisplayUseDefault + || in_array($attributeCode, $this->elementsWithUseConfigSetting) + ) { + continue; + } + + $meta = $this->getArrayManager()->merge( + [$attributePath, 'arguments/data/config'], + $meta, + [ + 'service' => [ + 'template' => 'ui/form/element/helper/service', + ], + 'disabled' => !$this->getScopeOverriddenValue()->containsValue( + CategoryInterface::class, + $category, + $attributeCode, + $this->request->getParam($this->requestScopeFieldName, Store::DEFAULT_STORE_ID) + ) + ] + ); + } + + return $meta; + } + + /** + * Removes not necessary inheritance fields + * + * @param Category $category + * @param array $meta + * @return array + */ + private function resolveParentInheritance(Category $category, array $meta) + { + if (!$category->getParentId() || !$this->getArrayManager()->findPath('custom_use_parent_settings', $meta)) { + return $meta; + } + + $meta = $this->getArrayManager()->merge( + [$this->getArrayManager()->findPath('custom_use_parent_settings', $meta), 'arguments/data/config'], + $meta, + ['visible' => false] + ); + + return $meta; } /** @@ -203,14 +308,10 @@ public function getData() $category = $this->getCurrentCategory(); if ($category) { $categoryData = $category->getData(); - $categoryData = $this->addUseDefaultSettings($category, $categoryData); $categoryData = $this->addUseConfigSettings($categoryData); $categoryData = $this->filterFields($categoryData); - if (isset($categoryData['image'])) { - unset($categoryData['image']); - $categoryData['image'][0]['name'] = $category->getData('image'); - $categoryData['image'][0]['url'] = $category->getImageUrl(); - } + $categoryData = $this->convertValues($category, $categoryData); + $this->loadedData[$category->getId()] = $categoryData; } return $this->loadedData; @@ -294,6 +395,7 @@ protected function addUseConfigSettings($categoryData) * @param \Magento\Catalog\Model\Category $category * @param array $categoryData * @return array + * @deprecated */ protected function addUseDefaultSettings($category, $categoryData) { @@ -371,6 +473,39 @@ protected function filterFields($categoryData) return array_diff_key($categoryData, array_flip($this->ignoreFields)); } + /** + * Converts category image data to acceptable for rendering format + * + * @param \Magento\Catalog\Model\Category $category + * @param array $categoryData + * @return array + */ + private function convertValues($category, $categoryData) + { + foreach ($category->getAttributes() as $attributeCode => $attribute) { + if (!isset($categoryData[$attributeCode])) { + continue; + } + + if ($attribute->getBackend() instanceof ImageBackendModel) { + unset($categoryData[$attributeCode]); + + $fileName = $category->getData($attributeCode); + if ($this->getFileInfo()->isExist($fileName)) { + $stat = $this->getFileInfo()->getStat($fileName); + $mime = $this->getFileInfo()->getMimeType($fileName); + + $categoryData[$attributeCode][0]['name'] = $fileName; + $categoryData[$attributeCode][0]['url'] = $category->getImageUrl($attributeCode); + $categoryData['image'][0]['size'] = isset($stat) ? $stat['size'] : 0; + $categoryData['image'][0]['type'] = $mime; + } + } + } + + return $categoryData; + } + /** * Category's fields default values * @@ -383,15 +518,6 @@ public function getDefaultMetaData($result) $result['use_config.available_sort_by']['default'] = true; $result['use_config.default_sort_by']['default'] = true; $result['use_config.filter_price_range']['default'] = true; - if ($this->request->getParam('store') && $this->request->getParam('id')) { - $result['use_default.url_key']['checked'] = true; - $result['use_default.url_key']['default'] = true; - $result['use_default.url_key']['visible'] = true; - } else { - $result['use_default.url_key']['checked'] = false; - $result['use_default.url_key']['default'] = false; - $result['use_default.url_key']['visible'] = false; - } return $result; } @@ -431,7 +557,6 @@ protected function getFieldsMap() [ 'url_key', 'url_key_create_redirect', - 'use_default.url_key', 'url_key_group', 'meta_title', 'meta_keywords', @@ -461,4 +586,53 @@ protected function getFieldsMap() ], ]; } + + /** + * Retrieve scope overridden value + * + * @return ScopeOverriddenValue + * @deprecated + */ + private function getScopeOverriddenValue() + { + if (null === $this->scopeOverriddenValue) { + $this->scopeOverriddenValue = \Magento\Framework\App\ObjectManager::getInstance()->get( + ScopeOverriddenValue::class + ); + } + + return $this->scopeOverriddenValue; + } + + /** + * Retrieve array manager + * + * @return ArrayManager + * @deprecated + */ + private function getArrayManager() + { + if (null === $this->arrayManager) { + $this->arrayManager = \Magento\Framework\App\ObjectManager::getInstance()->get( + ArrayManager::class + ); + } + + return $this->arrayManager; + } + + /** + * Get FileInfo instance + * + * @return FileInfo + * + * @deprecated + */ + private function getFileInfo() + { + if ($this->fileInfo === null) { + $this->fileInfo = ObjectManager::getInstance()->get(FileInfo::class); + } + return $this->fileInfo; + } } diff --git a/app/code/Magento/Catalog/Model/Category/FileInfo.php b/app/code/Magento/Catalog/Model/Category/FileInfo.php new file mode 100644 index 0000000000000..9a4c1f9f243b3 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Category/FileInfo.php @@ -0,0 +1,107 @@ +filesystem = $filesystem; + $this->mime = $mime; + } + + /** + * Get WriteInterface instance + * + * @return WriteInterface + */ + private function getMediaDirectory() + { + if ($this->mediaDirectory === null) { + $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + } + return $this->mediaDirectory; + } + + /** + * Retrieve MIME type of requested file + * + * @param string $fileName + * @return string + */ + public function getMimeType($fileName) + { + $filePath = self::ENTITY_MEDIA_PATH . '/' . ltrim($fileName, '/'); + $absoluteFilePath = $this->getMediaDirectory()->getAbsolutePath($filePath); + + $result = $this->mime->getMimeType($absoluteFilePath); + return $result; + } + + /** + * Get file statistics data + * + * @param string $fileName + * @return array + */ + public function getStat($fileName) + { + $filePath = self::ENTITY_MEDIA_PATH . '/' . ltrim($fileName, '/'); + + $result = $this->getMediaDirectory()->stat($filePath); + return $result; + } + + /** + * Check if the file exists + * + * @param string $fileName + * @return bool + */ + public function isExist($fileName) + { + $filePath = self::ENTITY_MEDIA_PATH . '/' . ltrim($fileName, '/'); + + $result = $this->getMediaDirectory()->isExist($filePath); + return $result; + } +} diff --git a/app/code/Magento/Catalog/Model/Category/Link/ReadHandler.php b/app/code/Magento/Catalog/Model/Category/Link/ReadHandler.php index 6ac347cc1e4a2..4a76f0aea1595 100644 --- a/app/code/Magento/Catalog/Model/Category/Link/ReadHandler.php +++ b/app/code/Magento/Catalog/Model/Category/Link/ReadHandler.php @@ -1,6 +1,6 @@ _scopeConfig = $scopeConfig; $this->_configFactory = $configFactory; @@ -157,7 +160,14 @@ public function __construct( $this->_storeManager = $storeManager; $this->_eavConfig = $eavConfig; - parent::__construct($cache, $entityTypeFactory, $entityTypeCollectionFactory, $cacheState, $universalFactory); + parent::__construct( + $cache, + $entityTypeFactory, + $entityTypeCollectionFactory, + $cacheState, + $universalFactory, + $serializer + ); } /** diff --git a/app/code/Magento/Catalog/Model/Config/Backend/Category.php b/app/code/Magento/Catalog/Model/Config/Backend/Category.php index 4bb345b33d38e..2e1fcc2c42ac2 100644 --- a/app/code/Magento/Catalog/Model/Config/Backend/Category.php +++ b/app/code/Magento/Catalog/Model/Config/Backend/Category.php @@ -1,6 +1,6 @@ */ -class Price implements \Magento\Framework\Option\ArrayInterface +class Price implements ProductPriceOptionsInterface { /** * {@inheritdoc} @@ -20,8 +22,8 @@ class Price implements \Magento\Framework\Option\ArrayInterface public function toOptionArray() { return [ - ['value' => 'fixed', 'label' => __('Fixed')], - ['value' => 'percent', 'label' => __('Percent')] + ['value' => self::VALUE_FIXED, 'label' => __('Fixed')], + ['value' => self::VALUE_PERCENT, 'label' => __('Percent')], ]; } } diff --git a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/TierPrice.php b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/TierPrice.php new file mode 100644 index 0000000000000..ae3db1895b25b --- /dev/null +++ b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/TierPrice.php @@ -0,0 +1,27 @@ + self::VALUE_FIXED, 'label' => __('Fixed')], + ['value' => self::VALUE_PERCENT, 'label' => __('Discount')], + ]; + } +} diff --git a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php index 15c0941655d3b..423bbe5ca5781 100644 --- a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php +++ b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Type.php @@ -1,6 +1,6 @@ objectFactory = $objectFactory; $this->productOptionFactory = $productOptionFactory; $this->extensionFactory = $extensionFactory; $this->customOptionFactory = $customOptionFactory; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); } /** @@ -99,7 +110,7 @@ public function processOptions(CartItemInterface $cartItem) protected function getOptions(CartItemInterface $cartItem) { $buyRequest = !empty($cartItem->getOptionByCode('info_buyRequest')) - ? unserialize($cartItem->getOptionByCode('info_buyRequest')->getValue()) + ? $this->serializer->unserialize($cartItem->getOptionByCode('info_buyRequest')->getValue()) : null; return is_array($buyRequest) && isset($buyRequest['options']) ? $buyRequest['options'] diff --git a/app/code/Magento/Catalog/Model/Design.php b/app/code/Magento/Catalog/Model/Design.php index ad5cc4ff42fe0..136f36a2a1398 100644 --- a/app/code/Magento/Catalog/Model/Design.php +++ b/app/code/Magento/Catalog/Model/Design.php @@ -1,6 +1,6 @@ _productIndexerHelper->getAttribute('status'); @@ -263,7 +267,7 @@ protected function _fillTemporaryFlatTable(array $tables, $storeId, $valueFieldS $select->joinLeft( $temporaryTableName, - "e.entity_id = " . $temporaryTableName . ".entity_id", + sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryTableName), $columnsNames ); $allColumns = array_merge($allColumns, $columnsNames); @@ -277,7 +281,7 @@ protected function _fillTemporaryFlatTable(array $tables, $storeId, $valueFieldS if (!empty($columnValueNames)) { $select->joinLeft( $temporaryValueTableName, - "e.${linkField} = " . $temporaryValueTableName . ".entity_id", + sprintf('e.%1$s = %2$s.%1$s', $linkField, $temporaryValueTableName), $columnValueNames ); $allColumns = array_merge($allColumns, $columnValueNames); diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php index 0777e9a06e348..34bcfa2e484e5 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php @@ -1,6 +1,6 @@ tableInstance = $connection->newTable($tableName); + } + + /** + * @inheritdoc + */ + public function addColumn($name, $type, $size = null, $options = [], $comment = null) + { + $this->tableInstance->addColumn($name, $type, $size, $options, $comment); + return $this; + } + + /** + * @inheritdoc + */ + public function getTable() + { + return $this->tableInstance; + } +} diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/BuilderInterface.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/BuilderInterface.php new file mode 100644 index 0000000000000..3651821ae10ac --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Table/BuilderInterface.php @@ -0,0 +1,40 @@ +_connection->newTable($tableName); - $valueTemporaryTable = $this->_connection->newTable($valueTableName); + $temporaryTableBuilder = $this->getTableBuilderFactory()->create( + [ + 'connection' => $this->_connection, + 'tableName' => $tableName + ] + ); + $valueTemporaryTableBuilder = $this->getTableBuilderFactory()->create( + [ + 'connection' => $this->_connection, + 'tableName' => $valueTableName + ] + ); $flatColumns = $this->_productIndexerHelper->getFlatColumns(); - $temporaryTable->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); + $temporaryTableBuilder->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); - $temporaryTable->addColumn('type_id', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT); + $temporaryTableBuilder->addColumn('type_id', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT); - $temporaryTable->addColumn('attribute_set_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); + $temporaryTableBuilder->addColumn('attribute_set_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); - $valueTemporaryTable->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); + $valueTemporaryTableBuilder->addColumn('entity_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER); /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ foreach ($columns as $columnName => $attribute) { @@ -145,7 +160,7 @@ protected function _createTemporaryTable($tableName, array $columns, $valueField $column = $column[$attributeCode]; } - $temporaryTable->addColumn( + $temporaryTableBuilder->addColumn( $columnName, $column['type'], isset($column['length']) ? $column['length'] : null @@ -154,7 +169,7 @@ protected function _createTemporaryTable($tableName, array $columns, $valueField $columnValueName = $attributeCode . $valueFieldSuffix; if (isset($flatColumns[$columnValueName])) { $columnValue = $flatColumns[$columnValueName]; - $valueTemporaryTable->addColumn( + $valueTemporaryTableBuilder->addColumn( $columnValueName, $columnValue['type'], isset($columnValue['length']) ? $columnValue['length'] : null @@ -162,11 +177,11 @@ protected function _createTemporaryTable($tableName, array $columns, $valueField } } $this->_connection->dropTemporaryTable($tableName); - $this->_connection->createTemporaryTable($temporaryTable); + $this->_connection->createTemporaryTable($temporaryTableBuilder->getTable()); - if (count($valueTemporaryTable->getColumns()) > 1) { + if (count($valueTemporaryTableBuilder->getTable()->getColumns()) > 1) { $this->_connection->dropTemporaryTable($valueTableName); - $this->_connection->createTemporaryTable($valueTemporaryTable); + $this->_connection->createTemporaryTable($valueTemporaryTableBuilder->getTable()); $valueTables[$valueTableName] = $valueTableName; } } @@ -197,7 +212,8 @@ protected function _fillTemporaryEntityTable($tableName, array $columns, array $ if (!empty($columns)) { $select = $this->_connection->select(); $temporaryEntityTable = $this->_getTemporaryTableName($tableName); - $idsColumns = ['entity_id', 'type_id', 'attribute_set_id']; + $metadata = $this->getMetadataPool()->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); + $idsColumns = array_unique([$metadata->getLinkField(), 'entity_id', 'type_id', 'attribute_set_id']); $columns = array_merge($idsColumns, array_keys($columns)); @@ -261,7 +277,7 @@ protected function _fillTemporaryTable( ); $temporaryTableName = $this->_getTemporaryTableName($tableName); $temporaryValueTableName = $temporaryTableName . $valueFieldSuffix; - $keyColumn = ['entity_id']; + $keyColumn = array_unique([$metadata->getLinkField(), 'entity_id']); $columns = array_merge($keyColumn, array_keys($columnsList)); $valueColumns = $keyColumn; $flatColumns = $this->_productIndexerHelper->getFlatColumns(); @@ -333,6 +349,19 @@ protected function _fillTemporaryTable( } } + /** + * @return BuilderInterfaceFactory + */ + private function getTableBuilderFactory() + { + if (null === $this->tableBuilderFactory) { + $this->tableBuilderFactory = \Magento\Framework\App\ObjectManager::getInstance() + ->get(BuilderInterfaceFactory::class); + } + + return $this->tableBuilderFactory; + } + /** * @return \Magento\Framework\EntityManager\MetadataPool */ diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableData.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableData.php index a5a1b7d808f58..8f12fbfd358dc 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableData.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableData.php @@ -1,6 +1,6 @@ _defaultIndexerResource->getTable('catalog_product_index_tier_price'); $this->_emptyTable($table); + $tierPriceExpression = $this->_connection->getCheckSql( + 'tp.value = 0', + 'product_price.value * (1 - tp.percentage_value / 100)', + 'tp.value' + ); $websiteExpression = $this->_connection->getCheckSql( 'tp.website_id = 0', - 'ROUND(tp.value * cwd.rate, 4)', - 'tp.value' + 'ROUND(' . $tierPriceExpression . ' * cwd.rate, 4)', + $tierPriceExpression ); $linkField = $this->getProductIdFieldName(); + $priceAttribute = $this->getProductResource()->getAttribute('price'); + $select = $this->_connection->select()->from( ['cpe' => $this->_defaultIndexerResource->getTable('catalog_product_entity')], ['cpe.entity_id'] @@ -238,8 +250,15 @@ protected function _prepareTierPriceIndex($entityIds = null) ['cwd' => $this->_defaultIndexerResource->getTable('catalog_product_index_website')], 'cw.website_id = cwd.website_id', [] + )->join( + ['product_price' => $priceAttribute->getBackend()->getTable()], + 'tp.' . $linkField . ' = product_price.' . $linkField, + [] )->where( 'cw.website_id != 0' + )->where( + 'product_price.attribute_id = ?', + $priceAttribute->getAttributeId() )->columns( new \Zend_Db_Expr("MIN({$websiteExpression})") )->group( @@ -462,4 +481,17 @@ protected function getProductIdFieldName() $indexList = $this->_connection->getIndexList($table); return $indexList[$this->_connection->getPrimaryKeyName($table)]['COLUMNS_LIST'][0]; } + + /** + * @return \Magento\Catalog\Model\ResourceModel\Product + * @deprecated + */ + private function getProductResource() + { + if (null === $this->productResource) { + $this->productResource = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Catalog\Model\ResourceModel\Product::class); + } + return $this->productResource; + } } diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php index 69aeb81cf960c..8148703b1777c 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/Action/Full.php @@ -1,6 +1,6 @@ hasData('salable') && !$this->_catalogProduct->getSkipSaleableCheck()) { + return $this->getData('salable'); + } $this->_eventManager->dispatch('catalog_product_is_salable_before', ['product' => $this]); $salable = $this->isAvailable(); @@ -1626,6 +1628,7 @@ public function isSalable() 'catalog_product_is_salable_after', ['product' => $this, 'salable' => $object] ); + $this->setData('salable', $object->getIsSalable()); return $object->getIsSalable(); } @@ -1909,10 +1912,12 @@ public function addOption(Product\Option $option) */ public function getOptionById($optionId) { - /** @var \Magento\Catalog\Model\Product\Option $option */ - foreach ($this->getOptions() as $option) { - if ($option->getId() == $optionId) { - return $option; + if (is_array($this->getOptions())) { + /** @var \Magento\Catalog\Model\Product\Option $option */ + foreach ($this->getOptions() as $option) { + if ($option->getId() == $optionId) { + return $option; + } } } @@ -2272,7 +2277,7 @@ public function getIdentities() $identities[] = self::CACHE_PRODUCT_CATEGORY_TAG . '_' . $categoryId; } } - + if (($this->getOrigData('status') != $this->getData('status')) || $this->isStockStatusChanged()) { foreach ($this->getCategoryIds() as $categoryId) { $identities[] = self::CACHE_PRODUCT_CATEGORY_TAG . '_' . $categoryId; @@ -2287,7 +2292,7 @@ public function getIdentities() /** * Check whether stock status changed - * + * * @return bool */ private function isStockStatusChanged() @@ -2305,7 +2310,7 @@ private function isStockStatusChanged() && ($stockItem->getIsInStock() != $stockData['is_in_stock']) ); } - + /** * Reload PriceInfo object * @@ -2612,4 +2617,16 @@ private function getMediaGalleryProcessor() } return $this->mediaGalleryProcessor; } + + /** + * Set the associated products + * + * @param array $productIds + * @return $this + */ + public function setAssociatedProductIds(array $productIds) + { + $this->getExtensionAttributes()->setConfigurableProductLinks($productIds); + return $this; + } } diff --git a/app/code/Magento/Catalog/Model/Product/Action.php b/app/code/Magento/Catalog/Model/Product/Action.php index 45194cbee0261..84502202981f7 100644 --- a/app/code/Magento/Catalog/Model/Product/Action.php +++ b/app/code/Magento/Catalog/Model/Product/Action.php @@ -1,6 +1,6 @@ _catalogProductType = $catalogProductType; $this->_groupManagement = $groupManagement; - parent::__construct($currencyFactory, $storeManager, $catalogData, $config, $localeFormat); + parent::__construct( + $currencyFactory, + $storeManager, + $catalogData, + $config, + $localeFormat, + $scopeOverriddenValue + ); } /** @@ -129,6 +139,18 @@ protected function _getAdditionalUniqueFields($objectArray) return []; } + /** + * Get additional fields + * + * @param array $objectArray + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function getAdditionalFields($objectArray) + { + return []; + } + /** * Whether group price value fixed or percent of original price * @@ -176,9 +198,7 @@ public function validate($object) throw new \Magento\Framework\Exception\LocalizedException(__($this->_getDuplicateErrorMessage())); } - if (!$this->isPositiveOrZero($priceRow['price'])) { - return __('Group price must be a number greater than 0.'); - } + $this->validatePrice($priceRow); $duplicates[$compare] = true; } @@ -228,6 +248,20 @@ public function validate($object) return true; } + /** + * @param array $priceRow + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function validatePrice(array $priceRow) + { + if (!isset($priceRow['price']) || !$this->isPositiveOrZero($priceRow['price'])) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Group price must be a number greater than 0.') + ); + } + } + /** * Prepare group prices data for website * @@ -270,37 +304,70 @@ public function preparePriceData(array $priceData, $productTypeId, $websiteId) */ public function afterLoad($object) { - $storeId = $object->getStoreId(); + $data = $this->_getResource()->loadPriceData( + $object->getData($this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField()), + $this->getWebsiteId($object->getStoreId()) + ); + $this->setPriceData($object, $data); + + return $this; + } + + /** + * @param int $storeId + * @return int|null + */ + private function getWebsiteId($storeId) + { $websiteId = null; if ($this->getAttribute()->isScopeGlobal()) { $websiteId = 0; } elseif ($storeId) { $websiteId = $this->_storeManager->getStore($storeId)->getWebsiteId(); } + return $websiteId; + } - $data = $this->_getResource()->loadPriceData( - $object->getData($this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField()), - $websiteId - ); - foreach ($data as $k => $v) { - $data[$k]['website_price'] = $v['price']; - if ($v['all_groups']) { - $data[$k]['cust_group'] = $this->_groupManagement->getAllCustomersGroup()->getId(); - } - } - + /** + * @param \Magento\Catalog\Model\Product $object + * @param array $priceData + */ + public function setPriceData($object, $priceData) + { + $priceData = $this->modifyPriceData($object, $priceData); + $websiteId = $this->getWebsiteId($object->getStoreId()); if (!$object->getData('_edit_mode') && $websiteId) { - $data = $this->preparePriceData($data, $object->getTypeId(), $websiteId); + $priceData = $this->preparePriceData($priceData, $object->getTypeId(), $websiteId); } - $object->setData($this->getAttribute()->getName(), $data); - $object->setOrigData($this->getAttribute()->getName(), $data); + $object->setData($this->getAttribute()->getName(), $priceData); + $object->setOrigData($this->getAttribute()->getName(), $priceData); $valueChangedKey = $this->getAttribute()->getName() . '_changed'; $object->setOrigData($valueChangedKey, 0); $object->setData($valueChangedKey, 0); + } - return $this; + /** + * Perform price modification + * + * @param \Magento\Catalog\Model\Product $object + * @param array $data + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function modifyPriceData($object, $data) + { + /** @var array $priceItem */ + foreach ($data as $key => $priceItem) { + if (isset($priceItem['price']) && $priceItem['price'] > 0) { + $data[$key]['website_price'] = $priceItem['price']; + } + if ($priceItem['all_groups']) { + $data[$key]['cust_group'] = $this->_groupManagement->getAllCustomersGroup()->getId(); + } + } + return $data; } /** @@ -372,13 +439,13 @@ public function afterSave($object) $useForAllGroups = $data['cust_group'] == $this->_groupManagement->getAllCustomersGroup()->getId(); $customerGroupId = !$useForAllGroups ? $data['cust_group'] : 0; - $new[$key] = array_merge( + $this->getAdditionalFields($data), [ 'website_id' => $data['website_id'], 'all_groups' => $useForAllGroups ? 1 : 0, 'customer_group_id' => $customerGroupId, - 'value' => $data['price'], + 'value' => isset($data['price']) ? $data['price'] : null, ], $this->_getAdditionalUniqueFields($data) ); @@ -412,14 +479,7 @@ public function afterSave($object) } if (!empty($update)) { - foreach ($update as $k => $v) { - if ($old[$k]['price'] != $v['value']) { - $price = new \Magento\Framework\DataObject(['value_id' => $old[$k]['price_id'], 'value' => $v['value']]); - $this->_getResource()->savePriceData($price); - - $isChanged = true; - } - } + $isChanged = $this->updateValues($update, $old); } if ($isChanged) { @@ -430,6 +490,29 @@ public function afterSave($object) return $this; } + /** + * @param array $valuesToUpdate + * @param array $oldValues + * @return boolean + */ + protected function updateValues(array $valuesToUpdate, array $oldValues) + { + $isChanged = false; + foreach ($valuesToUpdate as $key => $value) { + if ($oldValues[$key]['price'] != $value['value']) { + $price = new \Magento\Framework\DataObject( + [ + 'value_id' => $oldValues[$key]['price_id'], + 'value' => $value['value'] + ] + ); + $this->_getResource()->savePriceData($price); + $isChanged = true; + } + } + return $isChanged; + } + /** * Retrieve data for update attribute * diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media/EntryConverterInterface.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media/EntryConverterInterface.php index 450961d8f6289..3b9f46cfa143f 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media/EntryConverterInterface.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media/EntryConverterInterface.php @@ -1,6 +1,6 @@ */ @@ -48,26 +49,33 @@ class Price extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend protected $localeFormat; /** - * Construct - * + * @var \Magento\Catalog\Model\Attribute\ScopeOverriddenValue + */ + private $scopeOverriddenValue; + + /** * @param \Magento\Directory\Model\CurrencyFactory $currencyFactory * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Catalog\Helper\Data $catalogData * @param \Magento\Framework\App\Config\ScopeConfigInterface $config * @param \Magento\Framework\Locale\FormatInterface $localeFormat + * @param ScopeOverriddenValue|null $scopeOverriddenValue */ public function __construct( \Magento\Directory\Model\CurrencyFactory $currencyFactory, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Catalog\Helper\Data $catalogData, \Magento\Framework\App\Config\ScopeConfigInterface $config, - \Magento\Framework\Locale\FormatInterface $localeFormat + \Magento\Framework\Locale\FormatInterface $localeFormat, + ScopeOverriddenValue $scopeOverriddenValue = null ) { $this->_currencyFactory = $currencyFactory; $this->_storeManager = $storeManager; $this->_helper = $catalogData; $this->_config = $config; $this->localeFormat = $localeFormat; + $this->scopeOverriddenValue = $scopeOverriddenValue + ?: \Magento\Framework\App\ObjectManager::getInstance()->get(ScopeOverriddenValue::class); } /** @@ -102,43 +110,29 @@ public function setScope($attribute) } /** - * After Save Attribute manipulation + * After Save Price Attribute manipulation + * Processes product price attributes if price scoped to website and updates data when: + * * Price changed for non-default store view - will update price for all stores assigned to current website. + * * Price will be changed according to store currency even if price changed in product with default store id. + * * In a case when price was removed for non-default store (use default option checked) the default store price + * * will be used instead * * @param \Magento\Catalog\Model\Product $object * @return $this - * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function afterSave($object) { - $value = $object->getData($this->getAttribute()->getAttributeCode()); - /** - * Orig value is only for existing objects - */ - $oridData = $object->getOrigData(); - $origValueExist = $oridData && array_key_exists($this->getAttribute()->getAttributeCode(), $oridData); - if ($object->getStoreId() != 0 || !$value || $origValueExist) { - return $this; - } - - if ($this->getAttribute()->getIsGlobal() == ScopedAttributeInterface::SCOPE_WEBSITE) { - $baseCurrency = $this->_config->getValue( - \Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE, - 'default' - ); - - $storeIds = $object->getStoreIds(); - if (is_array($storeIds)) { - foreach ($storeIds as $storeId) { - $storeCurrency = $this->_storeManager->getStore($storeId)->getBaseCurrencyCode(); - if ($storeCurrency == $baseCurrency) { - continue; - } - $rate = $this->_currencyFactory->create()->load($baseCurrency)->getRate($storeCurrency); - if (!$rate) { - $rate = 1; - } - $newValue = $value * $rate; - $object->addAttributeUpdate($this->getAttribute()->getAttributeCode(), $newValue, $storeId); + /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ + $attribute = $this->getAttribute(); + $attributeCode = $attribute->getAttributeCode(); + $value = $object->getData($attributeCode); + if ((float)$value > 0) { + if ($attribute->isScopeWebsite() && $object->getStoreId() != \Magento\Store\Model\Store::DEFAULT_STORE_ID) { + if ($this->isUseDefault($object)) { + $value = null; + } + foreach ((array)$object->getWebsiteStoreIds() as $storeId) { + $object->addAttributeUpdate($attributeCode, $value, $storeId); } } } @@ -146,6 +140,22 @@ public function afterSave($object) return $this; } + /** + * Check whether product uses default attribute's value in selected scope + * @param \Magento\Catalog\Model\Product $object + * @return bool + */ + private function isUseDefault($object) + { + $overridden = $this->scopeOverriddenValue->containsValue( + \Magento\Catalog\Api\Data\ProductInterface::class, + $object, + $this->getAttribute()->getAttributeCode(), + $object->getStoreId() + ); + return !$overridden; + } + /** * Validate * diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php index 327729cf83695..be98147abfc85 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Sku.php @@ -1,6 +1,6 @@ getAttribute(); $entity = $attribute->getEntity(); - $increment = $this->_getLastSimilarAttributeValueIncrement($attribute, $object); $attributeValue = $object->getData($attribute->getAttributeCode()); + $increment = null; while (!$entity->checkAttributeUniqueValue($attribute, $object)) { + if ($increment === null) { + $increment = $this->_getLastSimilarAttributeValueIncrement($attribute, $object); + } $sku = trim($attributeValue); if (strlen($sku . '-' . ++$increment) > self::SKU_MAX_LENGTH) { $sku = substr($sku, 0, -strlen($increment) - 1); diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php index 5c3fd4730aaed..b1b81512b53c4 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php @@ -1,6 +1,6 @@ getStockData() !== null || $stockData !== null) { + if ($object->getStockData() !== null && $stockData !== null) { $object->setStockData(array_replace((array)$object->getStockData(), (array)$stockData)); } $object->unsetData($this->getAttribute()->getAttributeCode()); diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php index fc0fc07d4d524..0153d2bfc5741 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -1,6 +1,6 @@ _productAttributeBackendTierprice = $productAttributeTierprice; parent::__construct( @@ -48,7 +52,8 @@ public function __construct( $config, $localeFormat, $catalogProductType, - $groupManagement + $groupManagement, + $scopeOverriddenValue ); } @@ -75,6 +80,18 @@ protected function _getAdditionalUniqueFields($objectArray) return $uniqueFields; } + /** + * @inheritdoc + */ + protected function getAdditionalFields($objectArray) + { + $percentageValue = $this->getPercentage($objectArray); + return [ + 'value' => $percentageValue ? null : $objectArray['price'], + 'percentage_value' => $percentageValue ?: null, + ]; + } + /** * Error message when duplicates * @@ -105,4 +122,90 @@ public function isScalar() { return false; } + + /** + * @inheritdoc + */ + public function validate($object) + { + $attribute = $this->getAttribute(); + $priceRows = $object->getData($attribute->getName()); + $priceRows = array_filter((array)$priceRows); + + foreach ($priceRows as $priceRow) { + $percentage = $this->getPercentage($priceRow); + if ($percentage !== null && (!$this->isPositiveOrZero($percentage) || $percentage > 100)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Percentage value must be a number between 0 and 100.') + ); + } + } + + return parent::validate($object); + } + + /** + * @inheritdoc + */ + protected function validatePrice(array $priceRow) + { + if (!$this->getPercentage($priceRow)) { + parent::validatePrice($priceRow); + } + } + + /** + * @inheritdoc + */ + protected function modifyPriceData($object, $data) + { + $data = parent::modifyPriceData($object, $data); + foreach ($data as $key => $tierPrice) { + if ($this->getPercentage($tierPrice)) { + $data[$key]['price'] = $object->getPrice() * (1 - $this->getPercentage($tierPrice) / 100); + $data[$key]['website_price'] = $object->getPrice() * (1 - $this->getPercentage($tierPrice) / 100); + } + } + return $data; + } + + /** + * @param array $valuesToUpdate + * @param array $oldValues + * @return boolean + */ + protected function updateValues(array $valuesToUpdate, array $oldValues) + { + $isChanged = false; + foreach ($valuesToUpdate as $key => $value) { + if ($oldValues[$key]['price'] != $value['value'] + || $this->getPercentage($oldValues[$key]) != $this->getPercentage($value) + ) { + $price = new \Magento\Framework\DataObject( + [ + 'value_id' => $oldValues[$key]['price_id'], + 'value' => $value['value'], + 'percentage_value' => $this->getPercentage($value) + ] + ); + $this->_getResource()->savePriceData($price); + + $isChanged = true; + } + } + return $isChanged; + } + + /** + * Check whether price has percentage value. + * + * @param array $priceRow + * @return null + */ + private function getPercentage($priceRow) + { + return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value']) + ? $priceRow['percentage_value'] + : null; + } } diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Weight.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Weight.php index 3dfb0040fe6ac..495c62b429365 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Weight.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Weight.php @@ -1,6 +1,6 @@ - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Catalog\Model\Product\Attribute; diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Management.php b/app/code/Magento/Catalog/Model/Product/Attribute/Management.php index fa9b2ddee3cfe..4529b61147402 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Management.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Management.php @@ -1,7 +1,7 @@ - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Catalog\Model\Product\Attribute; diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php b/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php index a41a89a4ac9f7..4025318faaa88 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Repository.php @@ -1,13 +1,14 @@ getAttributeCode()); } + // Attribute code must not be changed after attribute creation + $attribute->setAttributeCode($existingModel->getAttributeCode()); $attribute->setAttributeId($existingModel->getAttributeId()); $attribute->setIsUserDefined($existingModel->getIsUserDefined()); $attribute->setFrontendInput($existingModel->getFrontendInput()); if (is_array($attribute->getFrontendLabels())) { - $frontendLabel[0] = $existingModel->getDefaultFrontendLabel(); + $defaultFrontendLabel = $attribute->getDefaultFrontendLabel(); + $frontendLabel[0] = !empty($defaultFrontendLabel) + ? $defaultFrontendLabel + : $existingModel->getDefaultFrontendLabel(); foreach ($attribute->getFrontendLabels() as $item) { $frontendLabel[$item->getStoreId()] = $item->getLabel(); } $attribute->setDefaultFrontendLabel($frontendLabel); } - if (!$attribute->getIsUserDefined()) { - // Unset attribute field for system attributes - $attribute->setApplyTo(null); - } } else { $attribute->setAttributeId(null); @@ -176,8 +178,11 @@ public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attrib $attribute->setIsUserDefined(1); } $this->attributeResource->save($attribute); - foreach ($attribute->getOptions() as $option) { - $this->getOptionManagement()->add($attribute->getAttributeCode(), $option); + + if (!empty($attribute->getData(AttributeInterface::OPTIONS))) { + foreach ($attribute->getOptions() as $option) { + $this->getOptionManagement()->add($attribute->getAttributeCode(), $option); + } } return $this->get($attribute->getAttributeCode()); } diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/SetManagement.php b/app/code/Magento/Catalog/Model/Product/Attribute/SetManagement.php index d69e5a64939e9..e5ef94968d441 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/SetManagement.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/SetManagement.php @@ -1,7 +1,7 @@ _storeManager->getStore()->getCode(); if ($cache = $this->_configCacheType->load($cacheKey)) { - $options = unserialize($cache); + $options = $this->getSerializer()->unserialize($cache); } else { /** @var \Magento\Directory\Model\Country $country */ $country = $this->_countryFactory->create(); /** @var \Magento\Directory\Model\ResourceModel\Country\Collection $collection */ $collection = $country->getResourceCollection(); $options = $collection->load()->toOptionArray(); - $this->_configCacheType->save(serialize($options), $cacheKey); + $this->_configCacheType->save($this->getSerializer()->serialize($options), $cacheKey); } return $options; } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php b/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php index f43d106248ede..be839be021e84 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php @@ -1,6 +1,6 @@ mediaConfig->getMediaAttributeCodes() as $mediaAttrCode) { + foreach ($this->getMediaAttributeCodes() as $mediaAttrCode) { $attrData = $product->getData($mediaAttrCode); - + if (empty($attrData) && empty($clearImages) && empty($newImages) && empty($existImages)) { + continue; + } if (in_array($attrData, $clearImages)) { $product->setData($mediaAttrCode, 'no_selection'); } @@ -160,12 +167,13 @@ public function execute($product, $arguments = []) if (in_array($attrData, array_keys($existImages))) { $product->setData($mediaAttrCode . '_label', $existImages[$attrData]['label']); } - - $product->addAttributeUpdate( - $mediaAttrCode, - $product->getData($mediaAttrCode), - $product->getStoreId() - ); + if (!empty($product->getData($mediaAttrCode))) { + $product->addAttributeUpdate( + $mediaAttrCode, + $product->getData($mediaAttrCode), + $product->getStoreId() + ); + } } $product->setData($attrCode, $value); @@ -393,4 +401,17 @@ protected function copyImage($file) ); } } + + /** + * Get Media Attribute Codes cached value + * + * @return array + */ + private function getMediaAttributeCodes() + { + if ($this->mediaAttributeCodes === null) { + $this->mediaAttributeCodes = $this->mediaConfig->getMediaAttributeCodes(); + } + return $this->mediaAttributeCodes; + } } diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Entry.php b/app/code/Magento/Catalog/Model/Product/Gallery/Entry.php index cbe876561ad2e..8cfed2631994e 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Entry.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Entry.php @@ -1,7 +1,7 @@ $existingEntry) { + $entryTypes = (array)$entry->getTypes(); + $existingEntryTypes = (array)$existingMediaGalleryEntries[$key]->getTypes(); + $existingMediaGalleryEntries[$key]->setTypes(array_diff($existingEntryTypes, $entryTypes)); + if ($existingEntry->getId() == $entry->getId()) { $found = true; + if ($entry->getFile()) { + $entry->setId(null); + } $existingMediaGalleryEntries[$key] = $entry; - break; } } if (!$found) { diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/MimeTypeExtensionMap.php b/app/code/Magento/Catalog/Model/Product/Gallery/MimeTypeExtensionMap.php index e116e1b4f1cc8..4242539b9fe8b 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/MimeTypeExtensionMap.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/MimeTypeExtensionMap.php @@ -1,7 +1,7 @@ setData($attribute, null); + $product->setData($attribute, 'no_selection'); } } } elseif (in_array($mediaAttribute, $mediaAttributeCodes)) { - $product->setData($mediaAttribute, null); + $product->setData($mediaAttribute, 'no_selection'); } return $this; diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php index 8a3109f3507a0..1ed2ef20360e9 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php @@ -1,6 +1,6 @@ substituteNullsWithDefaultValues($mediaEntry); - $value['images'][] = $mediaEntry; + $value['images'][$mediaEntry['value_id']] = $mediaEntry; } $product->setData($attrCode, $value); } diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php index 45a6cf3db5f48..8085bf192aca9 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php @@ -1,6 +1,6 @@ resourceModel->countImageUses($image['file']) > 1) { + $filesToDelete[] = ltrim($image['file'], '/'); + } } } } diff --git a/app/code/Magento/Catalog/Model/Product/Image.php b/app/code/Magento/Catalog/Model/Product/Image.php index 7d8b464db3b34..03a3cdd044043 100644 --- a/app/code/Magento/Catalog/Model/Product/Image.php +++ b/app/code/Magento/Catalog/Model/Product/Image.php @@ -1,6 +1,6 @@ _coreFileStorageDatabase = $coreFileStorageDatabase; parent::__construct($context, $registry, $resource, $resourceCollection, $data); $this->_mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); - $result = $this->_mediaDirectory->create($this->_catalogProductMediaConfig->getBaseMediaPath()); $this->_imageFactory = $imageFactory; $this->_assetRepo = $assetRepo; $this->_viewFileSystem = $viewFileSystem; @@ -450,86 +464,29 @@ protected function _rgbToString($rgbArray) * @param string $file * @return $this * @throws \Exception - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) */ public function setBaseFile($file) { $this->_isBaseFilePlaceholder = false; - if ($file && 0 !== strpos($file, '/', 0)) { - $file = '/' . $file; - } - $baseDir = $this->_catalogProductMediaConfig->getBaseMediaPath(); - - if ('/no_selection' == $file) { - $file = null; - } - if ($file) { - if (!$this->_fileExists($baseDir . $file) || !$this->_checkMemory($baseDir . $file)) { - $file = null; - } - } - if (!$file) { + $this->imageAsset = $this->getViewAssetImageFactory()->create( + [ + 'miscParams' => $this->getMiscParams(), + 'filePath' => $file, + ] + ); + if ($file == 'no_selection' || !$this->_fileExists($this->imageAsset->getSourceFile()) + || !$this->_checkMemory($this->imageAsset->getSourceFile()) + ) { $this->_isBaseFilePlaceholder = true; - // check if placeholder defined in config - $isConfigPlaceholder = $this->_scopeConfig->getValue( - "catalog/placeholder/{$this->getDestinationSubdir()}_placeholder", - \Magento\Store\Model\ScopeInterface::SCOPE_STORE + $this->imageAsset = $this->getViewAssetPlaceholderFactory()->create( + [ + 'type' => $this->getDestinationSubdir(), + ] ); - $configPlaceholder = '/placeholder/' . $isConfigPlaceholder; - if (!empty($isConfigPlaceholder) && $this->_fileExists($baseDir . $configPlaceholder)) { - $file = $configPlaceholder; - } else { - $this->_newFile = true; - return $this; - } - } - - $baseFile = $baseDir . $file; - - if (!$file || !$this->_mediaDirectory->isFile($baseFile)) { - throw new \Exception(__('We can\'t find the image file.')); } - $this->_baseFile = $baseFile; - - // build new filename (most important params) - $path = [ - $this->_catalogProductMediaConfig->getBaseMediaPath(), - 'cache', - $this->_storeManager->getStore()->getId(), - $path[] = $this->getDestinationSubdir(), - ]; - if (!empty($this->_width) || !empty($this->_height)) { - $path[] = "{$this->_width}x{$this->_height}"; - } - - // add misk params as a hash - $miscParams = [ - ($this->_keepAspectRatio ? '' : 'non') . 'proportional', - ($this->_keepFrame ? '' : 'no') . 'frame', - ($this->_keepTransparency ? '' : 'no') . 'transparency', - ($this->_constrainOnly ? 'do' : 'not') . 'constrainonly', - $this->_rgbToString($this->_backgroundColor), - 'angle' . $this->_angle, - 'quality' . $this->_quality, - ]; - - // if has watermark add watermark params to hash - if ($this->getWatermarkFile()) { - $miscParams[] = $this->getWatermarkFile(); - $miscParams[] = $this->getWatermarkImageOpacity(); - $miscParams[] = $this->getWatermarkPosition(); - $miscParams[] = $this->getWatermarkWidth(); - $miscParams[] = $this->getWatermarkHeight(); - } - - $path[] = md5(implode('_', $miscParams)); - - // append prepared filename - $this->_newFile = implode('/', $path) . $file; - // the $file contains heading slash + $this->_baseFile = $this->imageAsset->getSourceFile(); return $this; } @@ -543,6 +500,7 @@ public function getBaseFile() } /** + * @deprecated * @return bool|string */ public function getNewFile() @@ -691,10 +649,10 @@ public function setWatermark( */ public function saveFile() { - if ($this->_isBaseFilePlaceholder && $this->_newFile === true) { + if ($this->_isBaseFilePlaceholder) { return $this; } - $filename = $this->_mediaDirectory->getAbsolutePath($this->getNewFile()); + $filename = $this->getBaseFile() ? $this->imageAsset->getPath() : null; $this->getImageProcessor()->save($filename); $this->_coreFileStorageDatabase->saveFile($filename); return $this; @@ -705,17 +663,7 @@ public function saveFile() */ public function getUrl() { - if ($this->_newFile === true) { - $url = $this->_assetRepo->getUrl( - "Magento_Catalog::images/product/placeholder/{$this->getDestinationSubdir()}.jpg" - ); - } else { - $url = $this->_storeManager->getStore()->getBaseUrl( - \Magento\Framework\UrlInterface::URL_TYPE_MEDIA - ) . $this->_newFile; - } - - return $url; + return $this->imageAsset->getUrl(); } /** @@ -741,9 +689,7 @@ public function getDestinationSubdir() */ public function isCached() { - if (is_string($this->_newFile)) { - return $this->_fileExists($this->_newFile); - } + return file_exists($this->imageAsset->getPath()); } /** @@ -940,18 +886,72 @@ protected function _fileExists($filename) */ public function getResizedImageInfo() { - $fileInfo = null; - if ($this->_newFile === true) { - $asset = $this->_assetRepo->createAsset( - "Magento_Catalog::images/product/placeholder/{$this->getDestinationSubdir()}.jpg" - ); - $img = $asset->getSourceFile(); - $fileInfo = getimagesize($img); + if ($this->isBaseFilePlaceholder() == true) { + $image = $this->imageAsset->getSourceFile(); } else { - if ($this->_mediaDirectory->isFile($this->_mediaDirectory->getAbsolutePath($this->_newFile))) { - $fileInfo = getimagesize($this->_mediaDirectory->getAbsolutePath($this->_newFile)); - } + $image = $this->imageAsset->getPath(); } - return $fileInfo; + return getimagesize($image); + } + + /** + * @return \Magento\Catalog\Model\View\Asset\ImageFactory + */ + private function getViewAssetImageFactory() + { + if ($this->viewAssetImageFactory == null) { + $this->viewAssetImageFactory = ObjectManager::getInstance()->get( + \Magento\Catalog\Model\View\Asset\ImageFactory::class + ); + } + + return $this->viewAssetImageFactory; + } + + /** + * @return \Magento\Catalog\Model\View\Asset\PlaceholderFactory + */ + private function getViewAssetPlaceholderFactory() + { + if ($this->viewAssetPlaceholderFactory == null) { + $this->viewAssetPlaceholderFactory = ObjectManager::getInstance()->get( + \Magento\Catalog\Model\View\Asset\PlaceholderFactory::class + ); + } + + return $this->viewAssetPlaceholderFactory; + } + + /** + * Retrieve misc params based on all image attributes + * + * @return array + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + private function getMiscParams() + { + $miscParams = [ + 'image_type' => $this->getDestinationSubdir(), + 'image_height' => $this->getHeight(), + 'image_width' => $this->getWidth(), + 'keep_aspect_ratio' => ($this->_keepAspectRatio ? '' : 'non') . 'proportional', + 'keep_frame' => ($this->_keepFrame ? '' : 'no') . 'frame', + 'keep_transparency' => ($this->_keepTransparency ? '' : 'no') . 'transparency', + 'constrain_only' => ($this->_constrainOnly ? 'do' : 'not') . 'constrainonly', + 'background' => $this->_rgbToString($this->_backgroundColor), + 'angle' => $this->_angle, + 'quality' => $this->_quality, + ]; + + // if has watermark add watermark params to hash + if ($this->getWatermarkFile()) { + $miscParams['watermark_file'] = $this->getWatermarkFile(); + $miscParams['watermark_image_opacity'] = $this->getWatermarkImageOpacity(); + $miscParams['watermark_position'] = $this->getWatermarkPosition(); + $miscParams['watermark_width'] = $this->getWatermarkWidth(); + $miscParams['watermark_height'] = $this->getWatermarkHeight(); + } + + return $miscParams; } } diff --git a/app/code/Magento/Catalog/Model/Product/Image/Cache.php b/app/code/Magento/Catalog/Model/Product/Image/Cache.php index 830e8be2f3852..2a5316583ff6e 100644 --- a/app/code/Magento/Catalog/Model/Product/Image/Cache.php +++ b/app/code/Magento/Catalog/Model/Product/Image/Cache.php @@ -1,6 +1,6 @@ metadataPool = $metadataPool; $this->linkResource = $linkResource; $this->productLinkRepository = $productLinkRepository; @@ -54,12 +53,18 @@ public function __construct( */ public function execute($entityType, $entity) { - /** @var \Magento\Catalog\Api\Data\ProductInterface $entity*/ - foreach ($this->productLinkRepository->getList($entity) as $link) { - $this->productLinkRepository->delete($link); + $link = $entity->getData($this->metadataPool->getMetadata($entityType)->getLinkField()); + if ($this->linkResource->hasProductLinks($link)) { + /** @var \Magento\Catalog\Api\Data\ProductInterface $entity*/ + foreach ($this->productLinkRepository->getList($entity) as $link) { + $this->productLinkRepository->delete($link); + } } - foreach ($entity->getProductLinks() as $link) { - $this->productLinkRepository->save($link); + $productLinks = $entity->getProductLinks(); + if (count($productLinks) > 0) { + foreach ($entity->getProductLinks() as $link) { + $this->productLinkRepository->save($link); + } } return $entity; } diff --git a/app/code/Magento/Catalog/Model/Product/LinkTypeProvider.php b/app/code/Magento/Catalog/Model/Product/LinkTypeProvider.php index 8a878e68957dc..e9f3e490bec57 100644 --- a/app/code/Magento/Catalog/Model/Product/LinkTypeProvider.php +++ b/app/code/Magento/Catalog/Model/Product/LinkTypeProvider.php @@ -2,7 +2,7 @@ /** * Collection of the available product link types * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Catalog\Model\Product; diff --git a/app/code/Magento/Catalog/Model/Product/Media/AttributeManagement.php b/app/code/Magento/Catalog/Model/Product/Media/AttributeManagement.php index 1bcc025fa2e7c..22f7690c8fc10 100644 --- a/app/code/Magento/Catalog/Model/Product/Media/AttributeManagement.php +++ b/app/code/Magento/Catalog/Model/Product/Media/AttributeManagement.php @@ -1,6 +1,6 @@ productRepository->get($productSku); $metadata = $this->getMetadataPool()->getMetadata(ProductInterface::class); $option->setData('product_id', $product->getData($metadata->getLinkField())); - $option->setOptionId(null); + $option->setData('store_id', $product->getStoreId()); + + if ($option->getOptionId()) { + $options = $product->getOptions(); + if (!$options) { + $options = $this->getProductOptions($product); + } + + $persistedOption = array_filter($options, function ($iOption) use ($option) { + return $option->getOptionId() == $iOption->getOptionId(); + }); + $persistedOption = reset($persistedOption); + + if (!$persistedOption) { + throw new NoSuchEntityException(); + } + $originalValues = $persistedOption->getValues(); + $newValues = $option->getData('values'); + if ($newValues) { + $newValues = $this->markRemovedValues($newValues, $originalValues); + $option->setData('values', $newValues); + } + } $option->save(); return $option; } diff --git a/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php b/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php index 7c32232b6591a..72241cbe6e701 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php @@ -1,6 +1,6 @@ getOptions(); + $optionIds = []; + + if ($options) { + $optionIds = array_map(function ($option) { + /** @var \Magento\Catalog\Model\Product\Option $option */ + return $option->getOptionId(); + }, $options); + } + /** @var \Magento\Catalog\Api\Data\ProductInterface $entity */ foreach ($this->optionRepository->getProductOptions($entity) as $option) { - $this->optionRepository->delete($option); + if (!in_array($option->getOptionId(), $optionIds)) { + $this->optionRepository->delete($option); + } } - if ($entity->getOptions()) { - foreach ($entity->getOptions() as $option) { + if ($options) { + foreach ($options as $option) { $this->optionRepository->save($option); } } + return $entity; } } diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type.php b/app/code/Magento/Catalog/Model/Product/Option/Type.php index 4b59ca40dfd79..893b91021b818 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Type.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Type.php @@ -1,6 +1,6 @@ _localeDate = $localeDate; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($checkoutSession, $scopeConfig, $data); } @@ -269,7 +280,7 @@ public function prepareOptionValueForRequest($optionValue) $confItem = $this->getConfigurationItem(); $infoBuyRequest = $confItem->getOptionByCode('info_buyRequest'); try { - $value = unserialize($infoBuyRequest->getValue()); + $value = $this->serializer->unserialize($infoBuyRequest->getValue()); if (is_array($value) && isset($value['options']) && isset($value['options'][$this->getOption()->getId()]) ) { return $value['options'][$this->getOption()->getId()]; diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php b/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php index 9c54207a3645d..b54266e17b402 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Type/DefaultType.php @@ -1,6 +1,6 @@ _itemOptionFactory = $itemOptionFactory; $this->_urlBuilder = $urlBuilder; $this->_escaper = $escaper; $this->_coreFileStorageDatabase = $coreFileStorageDatabase; + $this->filesystem = $filesystem ?: \Magento\Framework\App\ObjectManager::getInstance()->get(Filesystem::class); + $this->_rootDirectory = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA); $this->validatorInfo = $validatorInfo; $this->validatorFile = $validatorFile; + $this->serializer = $serializer ? $serializer : ObjectManager::getInstance()->get(Json::class); parent::__construct($checkoutSession, $scopeConfig, $data); } @@ -265,7 +285,7 @@ public function prepareForCart() // Save option in request, because we have no $_FILES['options'] $requestOptions[$this->getOption()->getId()] = $value; - $result = serialize($value); + $result = $this->serializer->serialize($value); } else { /* * Clear option info from request, so it won't be stored in our db upon @@ -296,7 +316,7 @@ public function getFormattedOptionValue($optionValue) { if ($this->_formattedOptionValue === null) { try { - $value = unserialize($optionValue); + $value = $this->serializer->unserialize($optionValue); $customOptionUrlParams = $this->getCustomOptionUrlParams() ? $this->getCustomOptionUrlParams() : [ 'id' => $this->getConfigurationItemOption()->getId(), @@ -306,7 +326,7 @@ public function getFormattedOptionValue($optionValue) $value['url'] = ['route' => $this->_customOptionDownloadUrl, 'params' => $customOptionUrlParams]; $this->_formattedOptionValue = $this->_getOptionHtml($value); - $this->getConfigurationItemOption()->setValue(serialize($value)); + $this->getConfigurationItemOption()->setValue($this->serializer->serialize($value)); return $this->_formattedOptionValue; } catch (\Exception $e) { return $optionValue; @@ -354,7 +374,7 @@ protected function _unserializeValue($value) if (is_array($value)) { return $value; } elseif (is_string($value) && !empty($value)) { - return unserialize($value); + return $this->serializer->unserialize($value); } else { return []; } @@ -376,11 +396,13 @@ public function getPrintableOptionValue($optionValue) * * @param string $optionValue Prepared for cart option value * @return string + * + * @deprecated */ public function getEditableOptionValue($optionValue) { try { - $value = unserialize($optionValue); + $value = $this->serializer->unserialize($optionValue); return sprintf( '%s [%d]', $this->_escaper->escapeHtml($value['title']), @@ -399,6 +421,8 @@ public function getEditableOptionValue($optionValue) * @return string|null * * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * + * @deprecated */ public function parseOptionValue($optionValue, $productOptionValues) { @@ -407,7 +431,7 @@ public function parseOptionValue($optionValue, $productOptionValues) $confItemOptionId = $matches[1]; $option = $this->_itemOptionFactory->create()->load($confItemOptionId); try { - unserialize($option->getValue()); + $this->serializer->unserialize($option->getValue()); return $option->getValue(); } catch (\Exception $e) { return null; @@ -426,7 +450,7 @@ public function parseOptionValue($optionValue, $productOptionValues) public function prepareOptionValueForRequest($optionValue) { try { - $result = unserialize($optionValue); + $result = $this->serializer->unserialize($optionValue); return $result; } catch (\Exception $e) { return null; @@ -442,7 +466,7 @@ public function copyQuoteToOrder() { $quoteOption = $this->getConfigurationItemOption(); try { - $value = unserialize($quoteOption->getValue()); + $value = $this->serializer->unserialize($quoteOption->getValue()); if (!isset($value['quote_path'])) { throw new \Exception(); } diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidateFactory.php b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidateFactory.php index 71011fe55072d..8d12349af0354 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidateFactory.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidateFactory.php @@ -1,6 +1,6 @@ getProduct()->getStoreId(); } foreach ($values as $value) { + if (isset($value['is_delete']) && (bool)$value['is_delete']) { + continue; + } $type = isset($value['price_type']) ? $value['price_type'] : null; $price = isset($value['price']) ? $value['price'] : null; $title = isset($value['title']) ? $value['title'] : null; diff --git a/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php b/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php index 84d2439097185..ebc7a6ba71e59 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Validator/Text.php @@ -1,6 +1,6 @@ getOption()->getStoreId() ); - $this->unsetData('option_type_id'); + if ($this->getData('is_delete') == '1') { if ($this->getId()) { $this->deleteValues($this->getId()); diff --git a/app/code/Magento/Catalog/Model/Product/Price/BasePrice.php b/app/code/Magento/Catalog/Model/Product/Price/BasePrice.php new file mode 100644 index 0000000000000..0b3976b3857fc --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/BasePrice.php @@ -0,0 +1,79 @@ +setData(self::PRICE, $price); + } + + /** + * {@inheritdoc} + */ + public function getPrice() + { + return $this->getData(self::PRICE); + } + + /** + * {@inheritdoc} + */ + public function setStoreId($storeId) + { + return $this->setData(self::STORE_ID, $storeId); + } + + /** + * {@inheritdoc} + */ + public function getStoreId() + { + return $this->getData(self::STORE_ID); + } + + /** + * {@inheritdoc} + */ + public function setSku($sku) + { + return $this->setData(self::SKU, $sku); + } + + /** + * {@inheritdoc} + */ + public function getSku() + { + return $this->getData(self::SKU); + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes(\Magento\Catalog\Api\Data\BasePriceExtensionInterface $extensionAttributes) + { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/BasePriceStorage.php b/app/code/Magento/Catalog/Model/Product/Price/BasePriceStorage.php new file mode 100644 index 0000000000000..ec1aeee42d175 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/BasePriceStorage.php @@ -0,0 +1,228 @@ +pricePersistenceFactory = $pricePersistenceFactory; + $this->basePriceInterfaceFactory = $basePriceInterfaceFactory; + $this->productIdLocator = $productIdLocator; + $this->storeRepository = $storeRepository; + $this->productRepository = $productRepository; + $this->validationResult = $validationResult; + $this->allowedProductTypes = $allowedProductTypes; + $this->invalidSkuChecker = $invalidSkuChecker; + } + + /** + * {@inheritdoc} + */ + public function get(array $skus) + { + $this->invalidSkuChecker->isSkuListValid( + $skus, + $this->allowedProductTypes, + $this->priceTypeAllowed + ); + $rawPrices = $this->getPricePersistence()->get($skus); + $prices = []; + foreach ($rawPrices as $rawPrice) { + $price = $this->basePriceInterfaceFactory->create(); + $sku = $this->getPricePersistence() + ->retrieveSkuById($rawPrice[$this->getPricePersistence()->getEntityLinkField()], $skus); + $price->setSku($sku); + $price->setPrice($rawPrice['value']); + $price->setStoreId($rawPrice['store_id']); + $prices[] = $price; + } + + return $prices; + } + + /** + * {@inheritdoc} + */ + public function update(array $prices) + { + $prices = $this->retrieveValidPrices($prices); + $formattedPrices = []; + + foreach ($prices as $price) { + $ids = array_keys($this->productIdLocator->retrieveProductIdsBySkus([$price->getSku()])[$price->getSku()]); + foreach ($ids as $id) { + $formattedPrices[] = [ + 'store_id' => $price->getStoreId(), + $this->getPricePersistence()->getEntityLinkField() => $id, + 'value' => $price->getPrice(), + ]; + } + } + + $this->getPricePersistence()->update($formattedPrices); + + return $this->validationResult->getFailedItems(); + } + + /** + * Get price persistence. + * + * @return PricePersistence + */ + private function getPricePersistence() + { + if (!$this->pricePersistence) { + $this->pricePersistence = $this->pricePersistenceFactory->create(['attributeCode' => $this->attributeCode]); + } + + return $this->pricePersistence; + } + + /** + * Retrieve valid prices that do not contain any errors. + * + * @param \Magento\Catalog\Api\Data\BasePriceInterface[] $prices + * @return array + */ + private function retrieveValidPrices(array $prices) + { + $skus = array_unique( + array_map(function ($price) { + return $price->getSku(); + }, $prices) + ); + $invalidSkus = $this->invalidSkuChecker->retrieveInvalidSkuList( + $skus, + $this->allowedProductTypes, + $this->priceTypeAllowed + ); + + foreach ($prices as $id => $price) { + if (!$price->getSku() || in_array($price->getSku(), $invalidSkus)) { + $this->validationResult->addFailedItem( + $id, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'SKU', 'fieldValue' => $price->getSku()] + ); + } + if (null === $price->getPrice() || $price->getPrice() < 0) { + $this->validationResult->addFailedItem( + $id, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'Price', 'fieldValue' => $price->getPrice()] + ); + } + try { + $this->storeRepository->getById($price->getStoreId()); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->validationResult->addFailedItem( + $id, + __( + 'Requested store is not found. Row ID: SKU = %SKU, Store ID: %storeId.', + ['SKU' => $price->getSku(), 'storeId' => $price->getStoreId()] + ), + ['SKU' => $price->getSku(), 'storeId' => $price->getStoreId()] + ); + } + } + + foreach ($this->validationResult->getFailedRowIds() as $id) { + unset($prices[$id]); + } + + return $prices; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/Cost.php b/app/code/Magento/Catalog/Model/Product/Price/Cost.php new file mode 100644 index 0000000000000..f3991bf188187 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/Cost.php @@ -0,0 +1,79 @@ +setData(self::COST, $cost); + } + + /** + * {@inheritdoc} + */ + public function getCost() + { + return $this->getData(self::COST); + } + + /** + * {@inheritdoc} + */ + public function setStoreId($storeId) + { + return $this->setData(self::STORE_ID, $storeId); + } + + /** + * {@inheritdoc} + */ + public function getStoreId() + { + return $this->getData(self::STORE_ID); + } + + /** + * {@inheritdoc} + */ + public function setSku($sku) + { + return $this->setData(self::SKU, $sku); + } + + /** + * {@inheritdoc} + */ + public function getSku() + { + return $this->getData(self::SKU); + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes(\Magento\Catalog\Api\Data\CostExtensionInterface $extensionAttributes) + { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/CostStorage.php b/app/code/Magento/Catalog/Model/Product/Price/CostStorage.php new file mode 100644 index 0000000000000..6b2575d5eaf7f --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/CostStorage.php @@ -0,0 +1,219 @@ +pricePersistenceFactory = $pricePersistenceFactory; + $this->costInterfaceFactory = $costInterfaceFactory; + $this->productIdLocator = $productIdLocator; + $this->storeRepository = $storeRepository; + $this->validationResult = $validationResult; + $this->invalidSkuChecker = $invalidSkuChecker; + $this->allowedProductTypes = $allowedProductTypes; + } + + /** + * {@inheritdoc} + */ + public function get(array $skus) + { + $this->invalidSkuChecker->isSkuListValid($skus, $this->allowedProductTypes); + $rawPrices = $this->getPricePersistence()->get($skus); + $prices = []; + foreach ($rawPrices as $rawPrice) { + $price = $this->costInterfaceFactory->create(); + $sku = $this->getPricePersistence() + ->retrieveSkuById($rawPrice[$this->getPricePersistence()->getEntityLinkField()], $skus); + $price->setSku($sku); + $price->setCost($rawPrice['value']); + $price->setStoreId($rawPrice['store_id']); + $prices[] = $price; + } + + return $prices; + } + + /** + * {@inheritdoc} + */ + public function update(array $prices) + { + $prices = $this->retrieveValidPrices($prices); + $formattedPrices = []; + + foreach ($prices as $price) { + $productIdsBySkus = $this->productIdLocator->retrieveProductIdsBySkus([$price->getSku()]); + $productIds = array_keys($productIdsBySkus[$price->getSku()]); + foreach ($productIds as $id) { + $formattedPrices[] = [ + 'store_id' => $price->getStoreId(), + $this->getPricePersistence()->getEntityLinkField() => $id, + 'value' => $price->getCost(), + ]; + } + } + + $this->getPricePersistence()->update($formattedPrices); + + return $this->validationResult->getFailedItems(); + } + + /** + * {@inheritdoc} + */ + public function delete(array $skus) + { + $this->invalidSkuChecker->isSkuListValid($skus, $this->allowedProductTypes); + $this->getPricePersistence()->delete($skus); + + return true; + } + + /** + * Get price persistence. + * + * @return PricePersistence + */ + private function getPricePersistence() + { + if (!$this->pricePersistence) { + $this->pricePersistence = $this->pricePersistenceFactory->create(['attributeCode' => $this->attributeCode]); + } + + return $this->pricePersistence; + } + + /** + * Retrieve valid prices that do not contain any errors. + * + * @param array $prices + * @return array + */ + private function retrieveValidPrices(array $prices) + { + $skus = array_unique( + array_map(function ($price) { + return $price->getSku(); + }, $prices) + ); + $invalidSkus = $this->invalidSkuChecker->retrieveInvalidSkuList($skus, $this->allowedProductTypes); + + foreach ($prices as $id => $price) { + if (!$price->getSku() || in_array($price->getSku(), $invalidSkus)) { + $this->validationResult->addFailedItem( + $id, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'SKU', 'fieldValue' => $price->getSku()] + ); + } + if (null === $price->getCost() || $price->getCost() < 0) { + $this->validationResult->addFailedItem( + $id, + __( + 'Invalid attribute Cost = %cost. Row ID: SKU = %SKU, Store ID: %storeId.', + ['cost' => $price->getCost(), 'SKU' => $price->getSku(), 'storeId' => $price->getStoreId()] + ), + ['cost' => $price->getCost(), 'SKU' => $price->getSku(), 'storeId' => $price->getStoreId()] + ); + } + try { + $this->storeRepository->getById($price->getStoreId()); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->validationResult->addFailedItem( + $id, + __( + 'Requested store is not found. Row ID: SKU = %SKU, Store ID: %storeId.', + ['SKU' => $price->getSku(), 'storeId' => $price->getStoreId()] + ), + ['SKU' => $price->getSku(), 'storeId' => $price->getStoreId()] + ); + } + } + + foreach ($this->validationResult->getFailedRowIds() as $id) { + unset($prices[$id]); + } + + return $prices; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/InvalidSkuChecker.php b/app/code/Magento/Catalog/Model/Product/Price/InvalidSkuChecker.php new file mode 100644 index 0000000000000..c6a34bb803980 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/InvalidSkuChecker.php @@ -0,0 +1,86 @@ +productIdLocator = $productIdLocator; + $this->productRepository = $productRepository; + } + + /** + * Retrieve not found or invalid SKUs and and check that their type corresponds to allowed types list. + * + * @param array $skus + * @param array $allowedProductTypes + * @param int|bool $allowedPriceTypeValue + * @return array + */ + public function retrieveInvalidSkuList(array $skus, array $allowedProductTypes, $allowedPriceTypeValue = false) + { + $idsBySku = $this->productIdLocator->retrieveProductIdsBySkus($skus); + $existingSkus = array_keys($idsBySku); + $skuDiff = array_udiff( + $skus, + $existingSkus, + 'strcasecmp' + ); + + foreach ($idsBySku as $sku => $ids) { + foreach ($ids as $type) { + $valueTypeIsAllowed = false; + + if ($allowedPriceTypeValue + && $type == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE + && $this->productRepository->get($sku)->getPriceType() != $allowedPriceTypeValue + ) { + $valueTypeIsAllowed = true; + } + + if (!in_array($type, $allowedProductTypes) || $valueTypeIsAllowed) { + $skuDiff[] = $sku; + break; + } + } + } + + return $skuDiff; + } + + /** + * Check that SKU list is valid or return exception if it contains invalid values. + * + * @param array $skus + * @param array $allowedProductTypes + * @param int|bool $allowedPriceTypeValue + * @return void + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function isSkuListValid(array $skus, array $allowedProductTypes, $allowedPriceTypeValue = false) + { + $failedItems = $this->retrieveInvalidSkuList($skus, $allowedProductTypes, $allowedPriceTypeValue); + + if (!empty($failedItems)) { + $values = implode(', ', $failedItems); + $description = count($failedItems) == 1 + ? __('Requested product doesn\'t exist: %sku', ['sku' => $values]) + : __('Requested products don\'t exist: %sku', ['sku' => $values]); + throw new \Magento\Framework\Exception\NoSuchEntityException($description); + } + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/PricePersistence.php b/app/code/Magento/Catalog/Model/Product/Price/PricePersistence.php new file mode 100644 index 0000000000000..87effd3a58aba --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/PricePersistence.php @@ -0,0 +1,228 @@ +attributeResource = $attributeResource; + $this->attributeRepository = $attributeRepository; + $this->attributeCode = $attributeCode; + $this->productIdLocator = $productIdLocator; + $this->metadataPool = $metadataPool; + } + + /** + * Get prices by SKUs. + * + * @param array $skus + * @return array + */ + public function get(array $skus) + { + $ids = $this->retrieveAffectedIds($skus); + $select = $this->attributeResource->getConnection() + ->select() + ->from($this->attributeResource->getTable($this->table)); + return $this->attributeResource->getConnection()->fetchAll( + $select->where($this->getEntityLinkField() . ' IN (?)', $ids) + ->where('attribute_id = ?', $this->getAttributeId()) + ); + } + + /** + * Update prices. + * + * @param array $prices + * @return void + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + public function update(array $prices) + { + array_walk($prices, function (&$price) { + return $price['attribute_id'] = $this->getAttributeId(); + }); + $connection = $this->attributeResource->getConnection(); + $connection->beginTransaction(); + try { + foreach (array_chunk($prices, $this->itemsPerOperation) as $pricesBunch) { + $this->attributeResource->getConnection()->insertOnDuplicate( + $this->attributeResource->getTable($this->table), + $pricesBunch, + ['value'] + ); + } + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw new \Magento\Framework\Exception\CouldNotSaveException( + __('Could not save Prices.'), + $e + ); + } + } + + /** + * Delete product attribute by SKU. + * + * @param array $skus + * @return void + * @throws \Magento\Framework\Exception\CouldNotDeleteException + */ + public function delete(array $skus) + { + $ids = $this->retrieveAffectedIds($skus); + $connection = $this->attributeResource->getConnection(); + $connection->beginTransaction(); + try { + foreach (array_chunk($ids, $this->itemsPerOperation) as $idsBunch) { + $this->attributeResource->getConnection()->delete( + $this->attributeResource->getTable($this->table), + [ + 'attribute_id = ?' => $this->getAttributeId(), + $this->getEntityLinkField() . ' IN (?)' => $idsBunch + ] + ); + } + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw new \Magento\Framework\Exception\CouldNotDeleteException( + __('Could not delete Prices'), + $e + ); + } + } + + /** + * Retrieve SKU by product ID. + * + * @param int $id + * @param array $skus + * @return int|null + */ + public function retrieveSkuById($id, $skus) + { + foreach ($this->productIdLocator->retrieveProductIdsBySkus($skus) as $sku => $ids) { + if (false !== array_key_exists($id, $ids)) { + return $sku; + } + } + + return null; + } + + /** + * Get attribute ID. + * + * @return int + */ + private function getAttributeId() + { + if (!$this->attributeId) { + $this->attributeId = $this->attributeRepository->get($this->attributeCode)->getAttributeId(); + } + + return $this->attributeId; + } + + /** + * Retrieve affected product IDs. + * + * @param array $skus + * @return array + */ + private function retrieveAffectedIds(array $skus) + { + $affectedIds = []; + + foreach ($this->productIdLocator->retrieveProductIdsBySkus($skus) as $productIds) { + $affectedIds = array_merge($affectedIds, array_keys($productIds)); + } + + return array_unique($affectedIds); + } + + /** + * Get link field. + * + * @return string + */ + public function getEntityLinkField() + { + return $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) + ->getLinkField(); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/PriceUpdateResult.php b/app/code/Magento/Catalog/Model/Product/Price/PriceUpdateResult.php new file mode 100644 index 0000000000000..6922879d0fa93 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/PriceUpdateResult.php @@ -0,0 +1,64 @@ +getData(self::MESSAGE); + } + + /** + * {@inheritdoc} + */ + public function setMessage($message) + { + return $this->setData(self::MESSAGE, $message); + } + + /** + * {@inheritdoc} + */ + public function getParameters() + { + return $this->getData(self::PARAMETERS); + } + + /** + * {@inheritdoc} + */ + public function setParameters(array $parameters) + { + return $this->setData(self::PARAMETERS, $parameters); + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes( + \Magento\Catalog\Api\Data\PriceUpdateResultExtensionInterface $extensionAttributes + ) { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/SpecialPrice.php b/app/code/Magento/Catalog/Model/Product/Price/SpecialPrice.php new file mode 100644 index 0000000000000..e80f5ad29657f --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/SpecialPrice.php @@ -0,0 +1,112 @@ +setData(self::PRICE, $price); + } + + /** + * {@inheritdoc} + */ + public function getPrice() + { + return $this->getData(self::PRICE); + } + + /** + * {@inheritdoc} + */ + public function setStoreId($storeId) + { + return $this->setData(self::STORE_ID, $storeId); + } + + /** + * {@inheritdoc} + */ + public function getStoreId() + { + return $this->getData(self::STORE_ID); + } + + /** + * {@inheritdoc} + */ + public function setSku($sku) + { + return $this->setData(self::SKU, $sku); + } + + /** + * {@inheritdoc} + */ + public function getSku() + { + return $this->getData(self::SKU); + } + + /** + * {@inheritdoc} + */ + public function setPriceFrom($datetime) + { + return $this->setData(self::PRICE_FROM, $datetime); + } + + /** + * {@inheritdoc} + */ + public function getPriceFrom() + { + return $this->getData(self::PRICE_FROM); + } + + /** + * {@inheritdoc} + */ + public function setPriceTo($datetime) + { + return $this->setData(self::PRICE_TO, $datetime); + } + + /** + * {@inheritdoc} + */ + public function getPriceTo() + { + return $this->getData(self::PRICE_TO); + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes( + \Magento\Catalog\Api\Data\SpecialPriceExtensionInterface $extensionAttributes + ) { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/SpecialPriceStorage.php b/app/code/Magento/Catalog/Model/Product/Price/SpecialPriceStorage.php new file mode 100644 index 0000000000000..59220aaf22a1d --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/SpecialPriceStorage.php @@ -0,0 +1,298 @@ +specialPriceResource = $specialPriceResource; + $this->specialPriceFactory = $specialPriceFactory; + $this->productIdLocator = $productIdLocator; + $this->storeRepository = $storeRepository; + $this->validationResult = $validationResult; + $this->invalidSkuChecker = $invalidSkuChecker; + $this->allowedProductTypes = $allowedProductTypes; + } + + /** + * {@inheritdoc} + */ + public function get(array $skus) + { + $this->invalidSkuChecker->isSkuListValid($skus, $this->allowedProductTypes); + $rawPrices = $this->specialPriceResource->get($skus); + + $prices = []; + foreach ($rawPrices as $rawPrice) { + /** @var \Magento\Catalog\Api\Data\SpecialPriceInterface $price */ + $price = $this->specialPriceFactory->create(); + $sku = isset($rawPrice['sku']) + ? $rawPrice['sku'] + : $this->retrieveSkuById($rawPrice[$this->specialPriceResource->getEntityLinkField()], $skus); + $price->setSku($sku); + $price->setPrice($rawPrice['value']); + $price->setStoreId($rawPrice['store_id']); + $price->setPriceFrom($rawPrice['price_from']); + $price->setPriceTo($rawPrice['price_to']); + $prices[] = $price; + } + + return $prices; + } + + /** + * {@inheritdoc} + */ + public function update(array $prices) + { + $prices = $this->retrieveValidPrices($prices); + $this->specialPriceResource->update($prices); + + return $this->validationResult->getFailedItems(); + } + + /** + * {@inheritdoc} + */ + public function delete(array $prices) + { + $prices = $this->retrieveValidPrices($prices); + $this->specialPriceResource->delete($prices); + + return $this->validationResult->getFailedItems(); + } + + /** + * Retrieve prices with correct values. + * + * @param array $prices + * @return array + */ + private function retrieveValidPrices(array $prices) + { + $skus = array_unique( + array_map(function ($price) { + return $price->getSku(); + }, $prices) + ); + $failedSkus = $this->invalidSkuChecker->retrieveInvalidSkuList($skus, $this->allowedProductTypes); + + foreach ($prices as $key => $price) { + if (!$price->getSku() || in_array($price->getSku(), $failedSkus)) { + $this->validationResult->addFailedItem( + $key, + __( + 'Requested product doesn\'t exist. ' + . 'Row ID: SKU = %SKU, Store ID: %storeId, Price From: %priceFrom, Price To: %priceTo.', + [ + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ), + [ + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ); + } + $this->checkPrice($price, $key); + $this->checkDate($price, $price->getPriceFrom(), 'Price From', $key); + $this->checkDate($price, $price->getPriceTo(), 'Price To', $key); + try { + $this->storeRepository->getById($price->getStoreId()); + } catch (NoSuchEntityException $e) { + $this->validationResult->addFailedItem( + $key, + __( + 'Requested store is not found. ' + . 'Row ID: SKU = %SKU, Store ID: %storeId, Price From: %priceFrom, Price To: %priceTo.', + [ + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ), + [ + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ); + } + } + + foreach ($this->validationResult->getFailedRowIds() as $id) { + unset($prices[$id]); + } + + return $prices; + } + + /** + * Check that date value is correct and add error to aggregator if it contains incorrect data. + * + * @param \Magento\Catalog\Api\Data\SpecialPriceInterface $price + * @param string $value + * @param string $label + * @param int $key + * @return void + */ + private function checkDate(\Magento\Catalog\Api\Data\SpecialPriceInterface $price, $value, $label, $key) + { + if ($value && !$this->isCorrectDateValue($value)) { + $this->validationResult->addFailedItem( + $key, + __( + 'Invalid attribute %label = %priceTo. ' + . 'Row ID: SKU = %SKU, Store ID: %storeId, Price From: %priceFrom, Price To: %priceTo.', + [ + 'label' => $label, + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ), + [ + 'label' => $label, + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ); + } + } + + /** + * Check that provided price value is not empty and not lower then zero and add error to aggregator if price + * contains not valid data. + * + * @param \Magento\Catalog\Api\Data\SpecialPriceInterface $price + * @param int $key + * @return void + */ + private function checkPrice(\Magento\Catalog\Api\Data\SpecialPriceInterface $price, $key) + { + if (null === $price->getPrice() || $price->getPrice() < 0) { + $this->validationResult->addFailedItem( + $key, + __( + 'Invalid attribute Price = %price. ' + . 'Row ID: SKU = %SKU, Store ID: %storeId, Price From: %priceFrom, Price To: %priceTo.', + [ + 'price' => $price->getPrice(), + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ), + [ + 'price' => $price->getPrice(), + 'SKU' => $price->getSku(), + 'storeId' => $price->getStoreId(), + 'priceFrom' => $price->getPriceFrom(), + 'priceTo' => $price->getPriceTo() + ] + ); + } + } + + /** + * Retrieve SKU by product ID. + * + * @param int $productId + * @param array $skus + * @return string|null + */ + private function retrieveSkuById($productId, array $skus) + { + foreach ($this->productIdLocator->retrieveProductIdsBySkus($skus) as $sku => $ids) { + if (isset($ids[$productId])) { + return $sku; + } + } + + return null; + } + + /** + * Check that date value is correct. + * + * @param string $date + * @return bool + */ + private function isCorrectDateValue($date) + { + $actualDate = date('Y-m-d H:i:s', strtotime($date)); + return $actualDate && $actualDate === $date; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/TierPrice.php b/app/code/Magento/Catalog/Model/Product/Price/TierPrice.php new file mode 100644 index 0000000000000..0b61ae4bcbf0c --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/TierPrice.php @@ -0,0 +1,127 @@ +setData(self::PRICE, $price); + } + + /** + * {@inheritdoc} + */ + public function getPrice() + { + return $this->getData(self::PRICE); + } + + /** + * {@inheritdoc} + */ + public function setPriceType($type) + { + return $this->setData(self::PRICE_TYPE, $type); + } + + /** + * {@inheritdoc} + */ + public function getPriceType() + { + return $this->getData(self::PRICE_TYPE); + } + + /** + * {@inheritdoc} + */ + public function setWebsiteId($websiteId) + { + return $this->setData(self::WEBSITE_ID, $websiteId); + } + + /** + * {@inheritdoc} + */ + public function getWebsiteId() + { + return $this->getData(self::WEBSITE_ID); + } + + /** + * {@inheritdoc} + */ + public function setSku($sku) + { + return $this->setData(self::SKU, $sku); + } + + /** + * {@inheritdoc} + */ + public function getSku() + { + return $this->getData(self::SKU); + } + + /** + * {@inheritdoc} + */ + public function setCustomerGroup($group) + { + return $this->setData(self::CUSTOMER_GROUP, $group); + } + + /** + * {@inheritdoc} + */ + public function getCustomerGroup() + { + return $this->getData(self::CUSTOMER_GROUP); + } + + /** + * {@inheritdoc} + */ + public function setQuantity($quantity) + { + return $this->setData(self::QUANTITY, $quantity); + } + + /** + * {@inheritdoc} + */ + public function getQuantity() + { + return $this->getData(self::QUANTITY); + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->_getExtensionAttributes(); + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes(\Magento\Catalog\Api\Data\TierPriceExtensionInterface $extensionAttributes) + { + return $this->_setExtensionAttributes($extensionAttributes); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/TierPriceFactory.php b/app/code/Magento/Catalog/Model/Product/Price/TierPriceFactory.php new file mode 100644 index 0000000000000..1cc608f662570 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/TierPriceFactory.php @@ -0,0 +1,169 @@ +tierPriceFactory = $tierPriceFactory; + $this->tierPricePersistence = $tierPricePersistence; + $this->customerGroupRepository = $customerGroupRepository; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->filterBuilder = $filterBuilder; + } + + /** + * Create populated tier price DTO. + * + * @param array $rawPrice + * @param string $sku + * @return \Magento\Catalog\Api\Data\TierPriceInterface + */ + public function create(array $rawPrice, $sku) + { + $price = $this->tierPriceFactory->create(); + $price->setPrice(isset($rawPrice['percentage_value']) ? $rawPrice['percentage_value'] : $rawPrice['value']); + $price->setPriceType( + isset($rawPrice['percentage_value']) + ? TierPriceInterface::PRICE_TYPE_DISCOUNT + : TierPriceInterface::PRICE_TYPE_FIXED + ); + $price->setWebsiteId($rawPrice['website_id']); + $price->setSku($sku); + $price->setCustomerGroup( + $rawPrice['all_groups'] == $this->allGroupsId + ? $this->allGroupsValue + : $this->customerGroupRepository->getById($rawPrice['customer_group_id'])->getCode() + ); + $price->setQuantity($rawPrice['qty']); + + return $price; + } + + /** + * Build tier price skeleton that has DB consistent format. + * + * @param TierPriceInterface $price + * @param int $id + * @return array + */ + public function createSkeleton(TierPriceInterface $price, $id) + { + return [ + $this->tierPricePersistence->getEntityLinkField() => $id, + 'all_groups' => $this->retrievePriceForAllGroupsValue($price), + 'customer_group_id' => $this->retrievePriceForAllGroupsValue($price) === $this->allGroupsId + ? 0 + : $this->retrieveGroupValue(strtolower($price->getCustomerGroup())), + 'qty' => $price->getQuantity(), + 'value' => $price->getPriceType() === TierPriceInterface::PRICE_TYPE_FIXED + ? $price->getPrice() + : 0.00, + 'percentage_value' => $price->getPriceType() === TierPriceInterface::PRICE_TYPE_DISCOUNT + ? $price->getPrice() + : null, + 'website_id' => $price->getWebsiteId() + ]; + } + + /** + * Retrieve price for all groups value. + * + * @param TierPriceInterface $price + * @return int + */ + private function retrievePriceForAllGroupsValue(TierPriceInterface $price) + { + return strcasecmp($price->getCustomerGroup(), $this->allGroupsValue) === 0 ? $this->allGroupsId : 0; + } + + /** + * Retrieve customer group id by code. + * + * @param string $code + * @return int + * @throws NoSuchEntityException + */ + private function retrieveGroupValue($code) + { + if (!isset($this->customerGroupsByCode[$code])) { + $searchCriteria = $this->searchCriteriaBuilder->addFilters( + [ + $this->filterBuilder->setField('customer_group_code')->setValue($code)->create() + ] + ); + $items = $this->customerGroupRepository->getList($searchCriteria->create())->getItems(); + $item = array_shift($items); + $this->customerGroupsByCode[strtolower($item->getCode())] = $item->getId(); + } + + return $this->customerGroupsByCode[$code]; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/TierPricePersistence.php b/app/code/Magento/Catalog/Model/Product/Price/TierPricePersistence.php new file mode 100644 index 0000000000000..a7149a60c41a7 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/TierPricePersistence.php @@ -0,0 +1,166 @@ +tierpriceResource = $tierpriceResource; + $this->metadataPool = $metadataPool; + } + + /** + * Get tier prices by product IDs. + * + * @param array $ids + * @return array + */ + public function get(array $ids) + { + $select = $this->tierpriceResource->getConnection()->select()->from($this->tierpriceResource->getMainTable()); + return $this->tierpriceResource->getConnection()->fetchAll( + $select->where($this->getEntityLinkField() . ' IN (?)', $ids) + ); + } + + /** + * Update tier prices. + * + * @param array $prices + * @return void + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + public function update(array $prices) + { + $connection = $this->tierpriceResource->getConnection(); + $connection->beginTransaction(); + try { + foreach (array_chunk($prices, $this->itemsPerOperation) as $pricesBunch) { + $this->tierpriceResource->getConnection()->insertOnDuplicate( + $this->tierpriceResource->getMainTable(), + $pricesBunch, + ['value', 'percentage_value'] + ); + } + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw new \Magento\Framework\Exception\CouldNotSaveException( + __('Could not save Tier Prices'), + $e + ); + } + } + + /** + * Replace prices. + * + * @param array $prices + * @param array $ids + * @return void + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + public function replace(array $prices, array $ids) + { + $connection = $this->tierpriceResource->getConnection(); + $connection->beginTransaction(); + try { + foreach (array_chunk($ids, $this->itemsPerOperation) as $idsBunch) { + $this->tierpriceResource->getConnection()->delete( + $this->tierpriceResource->getMainTable(), + [$this->getEntityLinkField() . ' IN (?)' => $idsBunch] + ); + } + + foreach (array_chunk($prices, $this->itemsPerOperation) as $pricesBunch) { + $this->tierpriceResource->getConnection()->insertMultiple( + $this->tierpriceResource->getMainTable(), + $pricesBunch + ); + } + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw new \Magento\Framework\Exception\CouldNotSaveException( + __('Could not replace Tier Prices'), + $e + ); + } + } + + /** + * Delete tier prices by IDs. + * + * @param array $ids + * @return void + * @throws \Magento\Framework\Exception\CouldNotDeleteException + */ + public function delete(array $ids) + { + $connection = $this->tierpriceResource->getConnection(); + $connection->beginTransaction(); + try { + foreach (array_chunk($ids, $this->itemsPerOperation) as $idsBunch) { + $this->tierpriceResource->getConnection()->delete( + $this->tierpriceResource->getMainTable(), + ['value_id IN (?)' => $idsBunch] + ); + } + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw new \Magento\Framework\Exception\CouldNotDeleteException( + __('Could not delete Tier Prices'), + $e + ); + } + } + + /** + * Get link field. + * + * @return string + */ + public function getEntityLinkField() + { + return $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) + ->getLinkField(); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php b/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php new file mode 100644 index 0000000000000..8f2b16542b1ec --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/TierPriceStorage.php @@ -0,0 +1,354 @@ +tierPricePersistence = $tierPricePersistence; + $this->tierPriceValidator = $tierPriceValidator; + $this->tierPriceFactory = $tierPriceFactory; + $this->priceIndexer = $priceIndexer; + $this->productIdLocator = $productIdLocator; + $this->config = $config; + $this->typeList = $typeList; + } + + /** + * {@inheritdoc} + */ + public function get(array $skus) + { + $this->tierPriceValidator->validateSkus($skus); + + return $this->getExistingPrices($skus); + } + + /** + * {@inheritdoc} + */ + public function update(array $prices) + { + $affectedIds = $this->retrieveAffectedProductIdsForPrices($prices); + $skus = array_unique( + array_map(function ($price) { + return $price->getSku(); + }, $prices) + ); + $result = $this->tierPriceValidator->retrieveValidationResult($prices, $this->getExistingPrices($skus)); + $prices = $this->removeIncorrectPrices($prices, $result->getFailedRowIds()); + $formattedPrices = $this->retrieveFormattedPrices($prices); + $this->tierPricePersistence->update($formattedPrices); + $this->reindexPrices($affectedIds); + $this->invalidateFullPageCache(); + + return $result->getFailedItems(); + } + + /** + * {@inheritdoc} + */ + public function replace(array $prices) + { + $result = $this->tierPriceValidator->retrieveValidationResult($prices); + $prices = $this->removeIncorrectPrices($prices, $result->getFailedRowIds()); + $affectedIds = $this->retrieveAffectedProductIdsForPrices($prices); + $formattedPrices = $this->retrieveFormattedPrices($prices); + $this->tierPricePersistence->replace($formattedPrices, $affectedIds); + $this->reindexPrices($affectedIds); + $this->invalidateFullPageCache(); + + return $result->getFailedItems(); + } + + /** + * {@inheritdoc} + */ + public function delete(array $prices) + { + $affectedIds = $this->retrieveAffectedProductIdsForPrices($prices); + $result = $this->tierPriceValidator->retrieveValidationResult($prices); + $prices = $this->removeIncorrectPrices($prices, $result->getFailedRowIds()); + $priceIds = $this->retrieveAffectedPriceIds($prices); + $this->tierPricePersistence->delete($priceIds); + $this->reindexPrices($affectedIds); + $this->invalidateFullPageCache(); + + return $result->getFailedItems(); + } + + /** + * Get existing prices by SKUs. + * + * @param array $skus + * @return array + */ + private function getExistingPrices(array $skus) + { + $ids = $this->retrieveAffectedIds($skus); + $rawPrices = $this->tierPricePersistence->get($ids); + $prices = []; + + foreach ($rawPrices as $rawPrice) { + $sku = $this->retrieveSkuById($rawPrice[$this->tierPricePersistence->getEntityLinkField()], $skus); + $prices[] = $this->tierPriceFactory->create($rawPrice, $sku); + } + + return $prices; + } + + /** + * Retrieve formatted prices. + * + * @param array $prices + * @return array + */ + private function retrieveFormattedPrices(array $prices) + { + $formattedPrices = []; + + foreach ($prices as $price) { + $idsBySku = $this->productIdLocator->retrieveProductIdsBySkus([$price->getSku()]); + $ids = array_keys($idsBySku[$price->getSku()]); + foreach ($ids as $id) { + $formattedPrices[] = $this->tierPriceFactory->createSkeleton($price, $id); + } + } + + return $formattedPrices; + } + + /** + * Retrieve affected product IDs for prices. + * + * @param TierPriceInterface[] $prices + * @return array + */ + private function retrieveAffectedProductIdsForPrices(array $prices) + { + $skus = array_unique( + array_map(function ($price) { + return $price->getSku(); + }, $prices) + ); + + return $this->retrieveAffectedIds($skus); + } + + /** + * Retrieve affected product IDs. + * + * @param array $skus + * @return array + */ + private function retrieveAffectedIds(array $skus) + { + $affectedIds = []; + + foreach ($this->productIdLocator->retrieveProductIdsBySkus($skus) as $productId) { + $affectedIds = array_merge($affectedIds, array_keys($productId)); + } + + return array_unique($affectedIds); + } + + /** + * Retrieve affected price IDs. + * + * @param array $prices + * @return array + */ + private function retrieveAffectedPriceIds(array $prices) + { + $affectedIds = $this->retrieveAffectedProductIdsForPrices($prices); + $formattedPrices = $this->retrieveFormattedPrices($prices); + $existingPrices = $this->tierPricePersistence->get($affectedIds); + $priceIds = []; + + foreach ($formattedPrices as $price) { + $priceIds[] = $this->retrievePriceId($price, $existingPrices); + } + + return $priceIds; + } + + /** + * Look through provided price in list of existing prices and retrieve it's Id. + * + * @param array $price + * @param array $existingPrices + * @return int|null + */ + private function retrievePriceId(array $price, array $existingPrices) + { + $linkField = $this->tierPricePersistence->getEntityLinkField(); + + foreach ($existingPrices as $existingPrice) { + if ($existingPrice['all_groups'] == $price['all_groups'] + && $existingPrice['customer_group_id'] == $price['customer_group_id'] + && $existingPrice['qty'] == $price['qty'] + && $this->isCorrectPriceValue($existingPrice, $price) + && $existingPrice[$linkField] == $price[$linkField] + ) { + return $existingPrice['value_id']; + } + } + + return null; + } + + /** + * Check that price value or price percentage value is not equal to 0 and is not similar with existing value. + * + * @param array $existingPrice + * @param array $price + * @return bool + */ + private function isCorrectPriceValue(array $existingPrice, array $price) + { + return ($existingPrice['value'] != 0 && $existingPrice['value'] == $price['value']) + || ($existingPrice['percentage_value'] !== null + && $existingPrice['percentage_value'] == $price['percentage_value']); + } + + /** + * Retrieve SKU by product ID. + * + * @param int $id + * @param array $skus + * @return int|null + */ + private function retrieveSkuById($id, $skus) + { + foreach ($this->productIdLocator->retrieveProductIdsBySkus($skus) as $sku => $ids) { + if (false !== array_key_exists($id, $ids)) { + return $sku; + } + } + + return null; + } + + /** + * Invalidate full page cache. + * + * @return void + */ + private function invalidateFullPageCache() + { + if ($this->config->isEnabled()) { + $this->typeList->invalidate('full_page'); + } + } + + /** + * Reindex prices. + * + * @param array $ids + * @return void + */ + private function reindexPrices(array $ids) + { + foreach (array_chunk($ids, $this->indexerChunkValue) as $affectedIds) { + $this->priceIndexer->execute($affectedIds); + } + } + + /** + * Remove prices from price list by id list. + * + * @param array $prices + * @param array $ids + * @return array + */ + private function removeIncorrectPrices(array $prices, array $ids) + { + foreach ($ids as $id) { + unset($prices[$id]); + } + + return $prices; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/Validation/Result.php b/app/code/Magento/Catalog/Model/Product/Price/Validation/Result.php new file mode 100644 index 0000000000000..fd02d72f51036 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/Validation/Result.php @@ -0,0 +1,82 @@ +priceUpdateResultFactory = $priceUpdateResultFactory; + } + + /** + * Add failed price identified, message and message parameters, that occurred during price update. + * + * @param int $id Failed price identified. + * @param string $message Failure reason message. + * @param array $parameters (optional). Placeholder values in ['placeholder key' => 'placeholder value'] format + * for failure reason message. + * @return void + */ + public function addFailedItem($id, $message, array $parameters = []) + { + $this->failedItems[$id][] = [ + 'message' => $message, + 'parameters' => $parameters + ]; + } + + /** + * Get ids of rows, that contained errors during price update. + * + * @return int[] + */ + public function getFailedRowIds() + { + return $this->failedItems ? array_keys($this->failedItems) : []; + } + + /** + * Get price update errors, that occurred during price update. + * + * @return \Magento\Catalog\Api\Data\PriceUpdateResultInterface[] + */ + public function getFailedItems() + { + $failedItems = []; + + foreach ($this->failedItems as $items) { + foreach ($items as $failedRecord) { + $resultItem = $this->priceUpdateResultFactory->create(); + $resultItem->setMessage($failedRecord['message']); + $resultItem->setParameters($failedRecord['parameters']); + $failedItems[] = $resultItem; + } + } + + return $failedItems; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Price/Validation/TierPriceValidator.php b/app/code/Magento/Catalog/Model/Product/Price/Validation/TierPriceValidator.php new file mode 100644 index 0000000000000..e52aae5d87e04 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Price/Validation/TierPriceValidator.php @@ -0,0 +1,414 @@ +productIdLocator = $productIdLocator; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->filterBuilder = $filterBuilder; + $this->customerGroupRepository = $customerGroupRepository; + $this->websiteRepository = $websiteRepository; + $this->tierPricePersistence = $tierPricePersistence; + $this->validationResult = $validationResult; + $this->invalidSkuChecker = $invalidSkuChecker; + $this->allowedProductTypes = $allowedProductTypes; + } + + /** + * Validate SKU. + * + * @param array $skus + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @return void + */ + public function validateSkus(array $skus) + { + $this->invalidSkuChecker->isSkuListValid($skus, $this->allowedProductTypes); + } + + /** + * Validate that prices have appropriate values and are unique and return result. + * + * @param array $prices + * @param array $existingPrices + * @return \Magento\Catalog\Model\Product\Price\Validation\Result $validationResult + */ + public function retrieveValidationResult(array $prices, array $existingPrices = []) + { + $validationResult = clone $this->validationResult; + $skus = array_unique( + array_map(function ($price) { + return $price->getSku(); + }, $prices) + ); + $skuDiff = $this->invalidSkuChecker->retrieveInvalidSkuList($skus, $this->allowedProductTypes); + $idsBySku = $this->productIdLocator->retrieveProductIdsBySkus($skus); + + $pricesBySku = []; + + foreach ($prices as $price) { + $pricesBySku[$price->getSku()][] = $price; + } + + foreach ($prices as $key => $price) { + $this->checkSku($price, $key, $skuDiff, $validationResult); + $this->checkPrice($price, $key, $validationResult); + $ids = isset($idsBySku[$price->getSku()]) ? $idsBySku[$price->getSku()] : []; + $this->checkPriceType($price, $ids, $key, $validationResult); + $this->checkQuantity($price, $key, $validationResult); + $this->checkWebsite($price, $key, $validationResult); + if (isset($pricesBySku[$price->getSku()])) { + $this->checkUnique($price, $pricesBySku[$price->getSku()], $key, $validationResult); + } + $this->checkUnique($price, $existingPrices, $key, $validationResult); + $this->checkGroup($price, $key, $validationResult); + } + + return $validationResult; + } + + /** + * Check that sku value is correct. + * + * @param \Magento\Catalog\Api\Data\TierPriceInterface $price + * @param int $key + * @param array $invalidSkus + * @param Result $validationResult + * @return void + */ + private function checkSku( + \Magento\Catalog\Api\Data\TierPriceInterface $price, + $key, + array $invalidSkus, + Result $validationResult + ) { + if (!$price->getSku() || in_array($price->getSku(), $invalidSkus)) { + $validationResult->addFailedItem( + $key, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'SKU', 'fieldValue' => $price->getSku()] + ); + } + } + + /** + * Verify that price value is correct. + * + * @param \Magento\Catalog\Api\Data\TierPriceInterface $price + * @param int $key + * @param Result $validationResult + * @return void + */ + private function checkPrice(\Magento\Catalog\Api\Data\TierPriceInterface $price, $key, Result $validationResult) + { + if ( + null === $price->getPrice() + || $price->getPrice() < 0 + || ($price->getPriceType() === \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT + && $price->getPrice() > 100 + ) + ) { + $validationResult->addFailedItem( + $key, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'Price', 'fieldValue' => $price->getPrice()] + ); + } + } + + /** + * Verify that price type is correct. + * + * @param \Magento\Catalog\Api\Data\TierPriceInterface $price + * @param array $ids + * @param int $key + * @param Result $validationResult + * @return void + */ + private function checkPriceType( + \Magento\Catalog\Api\Data\TierPriceInterface $price, + array $ids, + $key, + Result $validationResult + ) { + if ( + !in_array( + $price->getPriceType(), + [ + \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_FIXED, + \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT + ] + ) + || (array_search(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE, $ids) + && $price->getPriceType() !== \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT) + ) { + $validationResult->addFailedItem( + $key, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'Price Type', 'fieldValue' => $price->getPriceType()] + ); + } + } + + /** + * Verify that product quantity is correct. + * + * @param \Magento\Catalog\Api\Data\TierPriceInterface $price + * @param int $key + * @param Result $validationResult + * @return void + */ + private function checkQuantity(\Magento\Catalog\Api\Data\TierPriceInterface $price, $key, Result $validationResult) + { + if ($price->getQuantity() < 1) { + $validationResult->addFailedItem( + $key, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'Quantity', 'fieldValue' => $price->getQuantity()] + ); + } + } + + /** + * Verify that website exists. + * + * @param \Magento\Catalog\Api\Data\TierPriceInterface $price + * @param int $key + * @param Result $validationResult + * @return void + */ + private function checkWebsite(\Magento\Catalog\Api\Data\TierPriceInterface $price, $key, Result $validationResult) + { + try { + $this->websiteRepository->getById($price->getWebsiteId()); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $validationResult->addFailedItem( + $key, + __( + 'Invalid attribute %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + ['fieldName' => 'Website Id', 'fieldValue' => $price->getWebsiteId()] + ); + } + } + + /** + * Check website value is unique. + * + * @param \Magento\Catalog\Api\Data\TierPriceInterface $tierPrice + * @param array $prices + * @param int $key + * @param Result $validationResult + * @return void + */ + private function checkUnique( + \Magento\Catalog\Api\Data\TierPriceInterface $tierPrice, + array $prices, + $key, + Result $validationResult + ) { + foreach ($prices as $price) { + if ( + $price->getSku() === $tierPrice->getSku() + && strtolower($price->getCustomerGroup()) === strtolower($tierPrice->getCustomerGroup()) + && $price->getQuantity() == $tierPrice->getQuantity() + && ( + ($price->getWebsiteId() == $this->allWebsitesValue + || $tierPrice->getWebsiteId() == $this->allWebsitesValue) + && $price->getWebsiteId() != $tierPrice->getWebsiteId() + ) + ) { + $validationResult->addFailedItem( + $key, + __( + 'We found a duplicate website, tier price, customer group and quantity:' + . ' %fieldName1 = %fieldValue1, %fieldName2 = %fieldValue2, %fieldName3 = %fieldValue3.', + [ + 'fieldName1' => '%fieldName1', + 'fieldValue1' => '%fieldValue1', + 'fieldName2' => '%fieldName2', + 'fieldValue2' => '%fieldValue2', + 'fieldName3' => '%fieldName3', + 'fieldValue3' => '%fieldValue3' + ] + ), + [ + 'fieldName1' => 'Customer Group', + 'fieldValue1' => $price->getCustomerGroup(), + 'fieldName2' => 'Website Id', + 'fieldValue2' => $price->getWebsiteId(), + 'fieldName3' => 'Quantity', + 'fieldValue3' => $price->getQuantity(), + ] + ); + } + } + } + + /** + * Check customer group exists and has correct value. + * + * @param \Magento\Catalog\Api\Data\TierPriceInterface $price + * @param int $key + * @param Result $validationResult + * @return void + */ + private function checkGroup(\Magento\Catalog\Api\Data\TierPriceInterface $price, $key, Result $validationResult) + { + $customerGroup = strtolower($price->getCustomerGroup()); + + if ($customerGroup != $this->allGroupsValue && false === $this->retrieveGroupValue($customerGroup)) { + $validationResult->addFailedItem( + $key, + __( + 'No such entity with %fieldName = %fieldValue.', + ['fieldName' => '%fieldName', 'fieldValue' => '%fieldValue'] + ), + [ + 'fieldName' => 'Customer Group', + 'fieldValue' => $customerGroup, + ] + ); + } + } + + /** + * Retrieve customer group id by code. + * + * @param string $code + * @return int|bool + */ + private function retrieveGroupValue($code) + { + if (!isset($this->customerGroupsByCode[$code])) { + $searchCriteria = $this->searchCriteriaBuilder->addFilters( + [ + $this->filterBuilder->setField('customer_group_code')->setValue($code)->create() + ] + ); + $items = $this->customerGroupRepository->getList($searchCriteria->create())->getItems(); + $item = array_shift($items); + + if (!$item) { + return false; + } + + $this->customerGroupsByCode[strtolower($item->getCode())] = $item->getId(); + } + + return $this->customerGroupsByCode[$code]; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/PriceModifier.php b/app/code/Magento/Catalog/Model/Product/PriceModifier.php index 39d66054db014..2256ff3ae8d64 100644 --- a/app/code/Magento/Catalog/Model/Product/PriceModifier.php +++ b/app/code/Magento/Catalog/Model/Product/PriceModifier.php @@ -1,6 +1,6 @@ getCanShowPrice() !== false; + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Pricing/Renderer/SalableResolverInterface.php b/app/code/Magento/Catalog/Model/Product/Pricing/Renderer/SalableResolverInterface.php new file mode 100644 index 0000000000000..f019d5621e02b --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Pricing/Renderer/SalableResolverInterface.php @@ -0,0 +1,21 @@ +productRepository = $productRepository; + $this->storeManager = $storeManager; + $this->priceModifier = $priceModifier; + $this->config = $config; + $this->tierPriceManagement = $tierPriceManagement; + } + + /** + * {@inheritdoc} + */ + public function add($sku, ProductTierPriceInterface $tierPrice) + { + $product = $this->productRepository->get($sku, ['edit_mode' => true]); + $product->setTierPrices( + $this->prepareTierPrices($product->getTierPrices(), $tierPrice) + ); + try { + $this->productRepository->save($product); + } catch (\Exception $e) { + throw new \Magento\Framework\Exception\CouldNotSaveException(__('Could not save group price')); + } + return true; + } + + /** + * @param array $tierPrices + * @param ProductTierPriceInterface $tierPrice + * @return ProductTierPriceInterface[]|null + */ + private function prepareTierPrices(array $tierPrices, ProductTierPriceInterface $tierPrice) + { + $this->validate($tierPrice); + $websiteId = $this->getWebsiteId(); + + foreach ($tierPrices as $index => $item) { + $tierPriceWebsite = $tierPrice->getExtensionAttributes() + ? $tierPrice->getExtensionAttributes()->getWebsiteId() + : 0; + + if ($item->getCustomerGroupId() == $tierPrice->getCustomerGroupId() + && $websiteId == $tierPriceWebsite + && $item->getQty() == $tierPrice->getQty() + ) { + unset($tierPrices[$index]); + break; + } + } + + $tierPrices[] = $tierPrice; + return $tierPrices; + } + + /** + * @return int + */ + private function getWebsiteId() + { + $websiteIdentifier = 0; + $value = $this->config->getValue('catalog/price/scope', ScopeInterface::SCOPE_WEBSITE); + if ($value != 0) { + $websiteIdentifier = $this->storeManager->getWebsite()->getId(); + } + + return $websiteIdentifier; + } + + /** + * @param ProductTierPriceInterface $tierPrice + * @throws \Magento\Framework\Exception\InputException + * @return void + */ + private function validate(ProductTierPriceInterface $tierPrice) + { + $data = ['qty' => $tierPrice->getQty(), 'price' => $tierPrice->getValue()]; + foreach ($data as $value) { + if (!is_float($value) || $value <= 0) { + throw new \Magento\Framework\Exception\InputException(__('Please provide valid data')); + } + } + } + + /** + * {@inheritdoc} + */ + public function remove($sku, ProductTierPriceInterface $tierPrice) + { + $product = $this->productRepository->get($sku, ['edit_mode' => true]); + $this->priceModifier->removeTierPrice( + $product, + $tierPrice->getCustomerGroupId(), + $tierPrice->getQty(), + $this->getWebsiteId() + ); + return true; + } + + /** + * {@inheritdoc} + */ + public function getList($sku, $customerGroupId) + { + return $this->tierPriceManagement->getList($sku, $customerGroupId); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/TierPrice.php b/app/code/Magento/Catalog/Model/Product/TierPrice.php index 131280af1b1a4..6aee62b8b26a5 100644 --- a/app/code/Magento/Catalog/Model/Product/TierPrice.php +++ b/app/code/Magento/Catalog/Model/Product/TierPrice.php @@ -1,7 +1,6 @@ _catalogProductOption = $catalogProductOption; $this->_eavConfig = $eavConfig; @@ -195,6 +204,8 @@ public function __construct( $this->_filesystem = $filesystem; $this->_logger = $logger; $this->productRepository = $productRepository; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); } /** @@ -394,8 +405,7 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p $product->prepareCustomOptions(); $buyRequest->unsetData('_processing_params'); // One-time params only - $product->addCustomOption('info_buyRequest', serialize($buyRequest->getData())); - + $product->addCustomOption('info_buyRequest', $this->serializer->serialize($buyRequest->getData())); if ($options) { $optionIds = array_keys($options); $product->addCustomOption('option_ids', implode(',', $optionIds)); @@ -645,7 +655,7 @@ public function getOrderOptions($product) $optionArr = []; $info = $product->getCustomOption('info_buyRequest'); if ($info) { - $optionArr['info_buyRequest'] = unserialize($info->getValue()); + $optionArr['info_buyRequest'] = $this->serializer->unserialize($info->getValue()); } $optionIds = $product->getCustomOption('option_ids'); @@ -1092,4 +1102,15 @@ public function getAssociatedProducts($product) { return []; } + + /** + * Check if product can be potentially buyed from the category page or some other list + * + * @param \Magento\Catalog\Model\Product $product + * @return bool + */ + public function isPossibleBuyFromList($product) + { + return !$this->hasRequiredOptions($product); + } } diff --git a/app/code/Magento/Catalog/Model/Product/Type/Pool.php b/app/code/Magento/Catalog/Model/Product/Type/Pool.php index 84058a2fed4d5..0139c3cdae0fc 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/Pool.php +++ b/app/code/Magento/Catalog/Model/Product/Type/Pool.php @@ -1,6 +1,6 @@ getExistingPrices($product, 'tier_price'); foreach ($tierPrices as $price) { /** @var \Magento\Catalog\Api\Data\ProductTierPriceInterface $tierPrice */ - $tierPrice = $this->tierPriceFactory->create(); + $tierPrice = $this->tierPriceFactory->create() + ->setExtensionAttributes($this->getTierPriceExtensionAttributes()); $tierPrice->setCustomerGroupId($price['cust_group']); if (array_key_exists('website_price', $price)) { $value = $price['website_price']; @@ -363,11 +370,29 @@ public function getTierPrices($product) } $tierPrice->setValue($value); $tierPrice->setQty($price['price_qty']); + if (isset($price['percentage_value'])) { + $tierPrice->getExtensionAttributes()->setPercentageValue($price['percentage_value']); + } + $websiteId = isset($price['website_id']) ? $price['website_id'] : $this->getWebsiteForPriceScope(); + $tierPrice->getExtensionAttributes()->setWebsiteId($websiteId); $prices[] = $tierPrice; } return $prices; } + /** + * @deprecated + * @return \Magento\Catalog\Api\Data\ProductTierPriceExtensionInterface + */ + private function getTierPriceExtensionAttributes() + { + if (!$this->tierPriceExtensionFactory) { + $this->tierPriceExtensionFactory = \Magento\Framework\App\ObjectManager::getInstance() + ->get(ProductTierPriceExtensionFactory::class); + } + return $this->tierPriceExtensionFactory->create(); + } + /** * Sets list of product tier prices * @@ -382,19 +407,25 @@ public function setTierPrices($product, array $tierPrices = null) return $this; } - $websiteId = $this->getWebsiteForPriceScope(); $allGroupsId = $this->getAllCustomerGroupsId(); + $websiteId = $this->getWebsiteForPriceScope(); // build the new array of tier prices $prices = []; foreach ($tierPrices as $price) { + $extensionAttributes = $price->getExtensionAttributes(); + $priceWebsiteId = $websiteId; + if (isset($extensionAttributes) && is_numeric($extensionAttributes->getWebsiteId())) { + $priceWebsiteId = (string)$extensionAttributes->getWebsiteId(); + } $prices[] = [ - 'website_id' => $websiteId, + 'website_id' => $priceWebsiteId, 'cust_group' => $price->getCustomerGroupId(), 'website_price' => $price->getValue(), 'price' => $price->getValue(), 'all_groups' => ($price->getCustomerGroupId() == $allGroupsId), - 'price_qty' => $price->getQty() + 'price_qty' => $price->getQty(), + 'percentage_value' => $extensionAttributes ? $extensionAttributes->getPercentageValue() : null ]; } $product->setData('tier_price', $prices); diff --git a/app/code/Magento/Catalog/Model/Product/Type/Price/Factory.php b/app/code/Magento/Catalog/Model/Product/Type/Price/Factory.php index 257b0e8d0529d..6d1fc78798c99 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/Price/Factory.php +++ b/app/code/Magento/Catalog/Model/Product/Type/Price/Factory.php @@ -1,6 +1,6 @@ searchCriteriaBuilder = $searchCriteriaBuilder; + $this->filterBuilder = $filterBuilder; + $this->metadataPool = $metadataPool; + $this->productRepository = $productRepository; + } + + /** + * {@inheritdoc} + */ + public function retrieveProductIdsBySkus(array $skus) + { + $skus = array_map('trim', $skus); + $skusInCache = $this->idsBySku ? array_keys($this->idsBySku) : []; + $neededSkus = array_diff($skus, $skusInCache); + + if (!empty($neededSkus)) { + $searchCriteria = $this->searchCriteriaBuilder->addFilters( + [ + $this->filterBuilder + ->setField(\Magento\Catalog\Api\Data\ProductInterface::SKU) + ->setConditionType('in') + ->setValue($neededSkus) + ->create(), + ] + ); + $items = $this->productRepository->getList($searchCriteria->create())->getItems(); + $linkField = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) + ->getLinkField(); + + foreach ($items as $item) { + $this->idsBySku[$item->getSku()][$item->getData($linkField)] = $item->getTypeId(); + } + } + + return array_intersect_ukey( + $this->idsBySku, + array_flip($skus), + 'strcasecmp' + ); + } +} diff --git a/app/code/Magento/Catalog/Model/ProductIdLocatorInterface.php b/app/code/Magento/Catalog/Model/ProductIdLocatorInterface.php new file mode 100644 index 0000000000000..e296666e86c88 --- /dev/null +++ b/app/code/Magento/Catalog/Model/ProductIdLocatorInterface.php @@ -0,0 +1,20 @@ +getWebsiteIds(); + if (!$this->storeManager->hasSingleStore()) { - if ($this->storeManager->getStore()->getCode() == \Magento\Store\Model\Store::ADMIN_CODE) { - $websiteIds = array_keys($this->storeManager->getWebsites()); - } else { - $websiteIds = [$this->storeManager->getStore()->getWebsiteId()]; - } + $websiteIds = array_unique( + array_merge( + $websiteIds, + [$this->storeManager->getStore()->getWebsiteId()] + ) + ); + } - $product->setWebsiteIds(array_unique(array_merge($product->getWebsiteIds(), $websiteIds))); + if ($this->storeManager->getStore(true)->getCode() == \Magento\Store\Model\Store::ADMIN_CODE) { + $websiteIds = array_keys($this->storeManager->getWebsites()); } + + $product->setWebsiteIds($websiteIds); } /** @@ -633,6 +640,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr $collection->load(); + $collection->addCategoryIds(); $searchResult = $this->searchResultsFactory->create(); $searchResult->setSearchCriteria($searchCriteria); $searchResult->setItems($collection->getItems()); diff --git a/app/code/Magento/Catalog/Model/ProductType.php b/app/code/Magento/Catalog/Model/ProductType.php index 30119223ef74c..c1c0ecc82c4a0 100644 --- a/app/code/Magento/Catalog/Model/ProductType.php +++ b/app/code/Magento/Catalog/Model/ProductType.php @@ -2,7 +2,7 @@ /** * Product type * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Catalog\Model; diff --git a/app/code/Magento/Catalog/Model/ProductTypeList.php b/app/code/Magento/Catalog/Model/ProductTypeList.php index ad36a7736de66..3e9946f43ea95 100644 --- a/app/code/Magento/Catalog/Model/ProductTypeList.php +++ b/app/code/Magento/Catalog/Model/ProductTypeList.php @@ -2,7 +2,7 @@ /** * Product type provider * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Catalog\Model; diff --git a/app/code/Magento/Catalog/Model/ProductTypes/Config.php b/app/code/Magento/Catalog/Model/ProductTypes/Config.php index a80692cfaf945..2db4b59878e0c 100644 --- a/app/code/Magento/Catalog/Model/ProductTypes/Config.php +++ b/app/code/Magento/Catalog/Model/ProductTypes/Config.php @@ -1,23 +1,32 @@ getChildrenCount()) { $object->setChildrenCount(0); } - + $object->setAttributeSetId( + $object->getAttributeSetId() ?: $this->getEntityType()->getDefaultAttributeSetId() + ); if ($object->isObjectNew()) { if ($object->getPosition() === null) { $object->setPosition($this->_getMaxPosition($object->getPath()) + 1); @@ -573,22 +580,29 @@ public function getIsActiveAttributeId() */ public function findWhereAttributeIs($entityIdsFilter, $attribute, $expectedValue) { - $linkField = $this->getLinkField(); - $bind = ['attribute_id' => $attribute->getId(), 'value' => $expectedValue]; - $selectEntities = $this->getConnection()->select()->from( - ['ce' => $this->getTable('catalog_category_entity')], - ['entity_id'] - )->joinLeft( - ['ci' => $attribute->getBackend()->getTable()], - "ci.{$linkField} = ce.{$linkField} AND attribute_id = :attribute_id", - ['value'] - )->where( - 'ci.value = :value' - )->where( - 'ce.entity_id IN (?)', - $entityIdsFilter - ); - return $this->getConnection()->fetchCol($selectEntities, $bind); + $entityIdsFilterHash = md5(serialize($entityIdsFilter)); + + if (!isset($this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue])) { + $linkField = $this->getLinkField(); + $bind = ['attribute_id' => $attribute->getId(), 'value' => $expectedValue]; + $selectEntities = $this->getConnection()->select()->from( + ['ce' => $this->getTable('catalog_category_entity')], + ['entity_id'] + )->joinLeft( + ['ci' => $attribute->getBackend()->getTable()], + "ci.{$linkField} = ce.{$linkField} AND attribute_id = :attribute_id", + ['value'] + )->where( + 'ci.value = :value' + )->where( + 'ce.entity_id IN (?)', + $entityIdsFilter + ); + $this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue] = + $this->getConnection()->fetchCol($selectEntities, $bind); + } + + return $this->entitiesWhereAttributesIs[$entityIdsFilterHash][$attribute->getId()][$expectedValue]; } /** diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/AggregateCount.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/AggregateCount.php index 4599fc4a8428a..7d55ebc3e9f91 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/AggregateCount.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/AggregateCount.php @@ -1,6 +1,6 @@ getData(self::APPLY_TO)) { - if (is_array($this->getData(self::APPLY_TO))) { - return $this->getData(self::APPLY_TO); - } - return explode(',', $this->getData(self::APPLY_TO)); - } else { - return []; + $applyTo = $this->_getData(self::APPLY_TO) ?: []; + if (!is_array($applyTo)) { + $applyTo = explode(',', $applyTo); } + return $applyTo; } /** @@ -420,6 +417,9 @@ public function isIndexable() if ($this->getAttributeCode() == 'price') { return false; } + if ($this->getAttributeCode() == 'visibility') { + return true; + } if (!$this->getIsFilterableInSearch() && !$this->getIsVisibleInAdvancedSearch() && !$this->getIsFilterable()) { return false; diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Helper.php b/app/code/Magento/Catalog/Model/ResourceModel/Helper.php index 36dbf0b9739c7..d9490b418c37c 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Helper.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Helper.php @@ -1,6 +1,6 @@ productCategoryLink; } + + /** + * Extends parent method to be appropriate for product. + * Store id is required to correctly identify attribute value we are working with. + * + * {@inheritdoc} + */ + protected function getAttributeRow($entity, $object, $attribute) + { + $data = parent::getAttributeRow($entity, $object, $attribute); + $data['store_id'] = $object->getStoreId(); + return $data; + } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php index 7075e1e11d493..46ecffcb6f442 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Action.php @@ -1,6 +1,6 @@ getConnection(); + $select = $this->getSelect($websiteId); + $productIdFieldName = $this->getProductIdFieldName(); + $select->where("{$productIdFieldName} = ?", $productId); + + $this->_loadPriceDataSelect($select); + return $this->getConnection()->fetchAll($select); + } + + /** + * @param int|null $websiteId + * @return \Magento\Framework\DB\Select + */ + public function getSelect($websiteId = null) + { $columns = [ 'price_id' => $this->getIdFieldName(), 'website_id' => 'website_id', @@ -34,12 +47,8 @@ public function loadPriceData($productId, $websiteId = null) $columns = $this->_loadPriceDataColumns($columns); - $productIdFieldName = $this->getProductIdFieldName(); - $select = $connection->select() - ->from($this->getMainTable(), $columns) - ->where("{$productIdFieldName} = ?", $productId); - - $this->_loadPriceDataSelect($select); + $select = $this->getConnection()->select() + ->from($this->getMainTable(), $columns); if ($websiteId !== null) { if ($websiteId == '0') { @@ -48,8 +57,7 @@ public function loadPriceData($productId, $websiteId = null) $select->where('website_id IN(?)', [0, $websiteId]); } } - - return $connection->fetchAll($select); + return $select; } /** diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Image.php index b2448d1fa2041..b068b2c456714 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Image.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Attribute/Backend/Image.php @@ -1,6 +1,6 @@ moduleManager = $moduleManager; $this->_catalogProductFlatState = $catalogProductFlatState; @@ -316,7 +323,11 @@ public function __construct( $this->_resourceHelper = $resourceHelper; $this->dateTime = $dateTime; $this->_groupManagement = $groupManagement; - $this->_productLimitationFilters = $this->createLimitationFilters(); + $productLimitationFactory = $productLimitationFactory ?: ObjectManager::getInstance()->get( + \Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitationFactory::class + ); + $this->_productLimitationFilters = $productLimitationFactory->create(); + $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class); parent::__construct( $entityFactory, $logger, @@ -2090,12 +2101,13 @@ public function addTierPriceData() if ($this->getFlag('tier_price_added')) { return $this; } + $linkField = $this->getConnection()->getAutoIncrementField($this->getTable('catalog_product_entity')); $tierPrices = []; $productIds = []; foreach ($this->getItems() as $item) { - $productIds[] = $item->getId(); - $tierPrices[$item->getId()] = []; + $productIds[] = $item->getData($linkField); + $tierPrices[$item->getData($linkField)] = []; } if (!$productIds) { return $this; @@ -2103,57 +2115,27 @@ public function addTierPriceData() /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ $attribute = $this->getAttribute('tier_price'); + /* @var $backend \Magento\Catalog\Model\Product\Attribute\Backend\Tierprice */ + $backend = $attribute->getBackend(); $websiteId = 0; if (!$attribute->isScopeGlobal() && null !== $this->getStoreId()) { $websiteId = $this->_storeManager->getStore($this->getStoreId())->getWebsiteId(); } - $linkField = $this->getConnection()->getAutoIncrementField($this->getTable('catalog_product_entity')); - $connection = $this->getConnection(); - $columns = [ - 'price_id' => 'value_id', - 'website_id' => 'website_id', - 'all_groups' => 'all_groups', - 'cust_group' => 'customer_group_id', - 'price_qty' => 'qty', - 'price' => 'value', - 'product_id' => $linkField, - ]; - $select = $connection->select()->from( - $this->getTable('catalog_product_entity_tier_price'), - $columns - )->where( + $select = $backend->getResource()->getSelect($websiteId); + $select->columns(['product_id' => $linkField])->where( $linkField .' IN(?)', $productIds )->order( - [$linkField, 'qty'] + $linkField ); - if ($websiteId == 0) { - $select->where('website_id = ?', $websiteId); - } else { - $select->where('website_id IN(?)', [0, $websiteId]); - } - - foreach ($connection->fetchAll($select) as $row) { - $tierPrices[$row['product_id']][] = [ - 'website_id' => $row['website_id'], - 'cust_group' => $row['all_groups'] ? $this->_groupManagement->getAllCustomersGroup()->getId() : $row['cust_group'], - 'price_qty' => $row['price_qty'], - 'price' => $row['price'], - 'website_price' => $row['price'], - ]; + foreach ($this->getConnection()->fetchAll($select) as $row) { + $tierPrices[$row['product_id']][] = $row; } - /* @var $backend \Magento\Catalog\Model\Product\Attribute\Backend\Tierprice */ - $backend = $attribute->getBackend(); - foreach ($this->getItems() as $item) { - $data = $tierPrices[$item->getId()]; - if (!empty($data) && $websiteId) { - $data = $backend->preparePriceData($data, $item->getTypeId(), $websiteId); - } - $item->setData('tier_price', $data); + $backend->setPriceData($item, $tierPrices[$item->getData($linkField)]); } $this->setFlag('tier_price_added', true); @@ -2210,14 +2192,25 @@ public function addMediaGalleryData() ); $mediaGalleries = []; - $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField(); - + $linkField = $this->getProductEntityMetadata()->getLinkField(); + $items = $this->getItems(); + + $select->where( + 'entity.' . $linkField . ' IN (?)', + array_map( + function ($item) use ($linkField) { + return $item->getData($linkField); + }, + $items + ) + ); foreach ($this->getConnection()->fetchAll($select) as $row) { $mediaGalleries[$row[$linkField]][] = $row; } - foreach ($this->getItems() as $item) { - $mediaEntries = isset($mediaGalleries[$item->getId()]) ? $mediaGalleries[$item->getId()] : []; + foreach ($items as $item) { + $mediaEntries = isset($mediaGalleries[$item->getData($linkField)]) ? + $mediaGalleries[$item->getData($linkField)] : []; $this->getGalleryReadHandler()->addMediaDataToProduct($item, $mediaEntries); } @@ -2226,15 +2219,13 @@ public function addMediaGalleryData() } /** - * Get MetadataPool instance - * @return MetadataPool + * Get product entity metadata + * + * @return \Magento\Framework\EntityManager\EntityMetadataInterface */ - private function getMetadataPool() + public function getProductEntityMetadata() { - if (!$this->metadataPool) { - $this->metadataPool = ObjectManager::getInstance()->get(MetadataPool::class); - } - return $this->metadataPool; + return $this->metadataPool->getMetadata(ProductInterface::class); } /** @@ -2358,13 +2349,4 @@ public function getPricesCount() return $this->_pricesCount; } - - /** - * @return Collection\ProductLimitation - */ - private function createLimitationFilters() - { - return \Magento\Framework\App\ObjectManager::getInstance() - ->create(\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class); - } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection/ProductLimitation.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection/ProductLimitation.php index aba330bea0651..28fcb4ab5c405 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection/ProductLimitation.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection/ProductLimitation.php @@ -1,6 +1,6 @@ baseSelectProcessors = $baseSelectProcessors; + } + + /** + * @param Select $select + * @return Select + */ + public function process(Select $select) + { + foreach ($this->baseSelectProcessors as $baseSelectProcessor) { + $select = $baseSelectProcessor->process($select); + } + return $select; + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Flat.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Flat.php index 56f14d4c12577..2dd445377d6ea 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Flat.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Flat.php @@ -1,6 +1,6 @@ getConnection()->fetchAll($select); } + + /** + * Counts uses of this image. + * + * @param string $image + * @return int + */ + public function countImageUses($image) + { + $select = $this->getConnection()->select() + ->from([$this->getMainTableAlias() => $this->getMainTable()]) + ->where( + 'value = ?', + $image + ); + return count($this->getConnection()->fetchAll($select)); + } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/AbstractIndexer.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/AbstractIndexer.php index 44d9b1c0304a8..378a3ddf099ab 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/AbstractIndexer.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/AbstractIndexer.php @@ -1,6 +1,6 @@ joinLeft( ['e' => $this->getTable('catalog_product_entity')], 'e.' . $linkField .' = l.parent_id', - ['e.entity_id as parent_id'] + [] )->join( ['cs' => $this->getTable('store')], '', @@ -205,9 +205,17 @@ protected function _prepareRelationIndexSelect($parentIds = null) )->join( ['i' => $idxTable], 'l.child_id = i.entity_id AND cs.store_id = i.store_id', - ['attribute_id', 'store_id', 'value'] + [] )->group( - ['parent_id', 'i.attribute_id', 'i.store_id', 'i.value'] + ['parent_id', 'i.attribute_id', 'i.store_id', 'i.value', 'l.child_id'] + )->columns( + [ + 'parent_id' => 'e.entity_id', + 'attribute_id' => 'i.attribute_id', + 'store_id' => 'i.store_id', + 'value' => 'i.value', + 'source_id' => 'l.child_id' + ] ); if ($parentIds !== null) { $select->where('e.entity_id IN(?)', $parentIds); @@ -222,7 +230,7 @@ protected function _prepareRelationIndexSelect($parentIds = null) 'select' => $select, 'entity_field' => new \Zend_Db_Expr('l.parent_id'), 'website_field' => new \Zend_Db_Expr('cs.website_id'), - 'store_field' => new \Zend_Db_Expr('cs.store_id') + 'store_field' => new \Zend_Db_Expr('cs.store_id'), ] ); @@ -263,6 +271,8 @@ protected function _getIndexableAttributesCondition() 'ca.is_filterable_in_search > 0', 'ca.is_visible_in_advanced_search > 0', 'ca.is_filterable > 0', + // Visibility is attribute that isn't used by search, but required to determine is product should be shown + "ea.attribute_code = 'visibility'" ]; return implode(' OR ', $conditions); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php index e8d9889e68d59..76127b02d5fb9 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Decimal.php @@ -1,6 +1,6 @@ $productValueExpression, + 'source_id' => 'cpe.entity_id', ] ); @@ -116,7 +117,7 @@ protected function _prepareIndex($entityIds = null, $attributeId = null) 'select' => $select, 'entity_field' => new \Zend_Db_Expr('cpe.entity_id'), 'website_field' => new \Zend_Db_Expr('cs.website_id'), - 'store_field' => new \Zend_Db_Expr('cs.store_id') + 'store_field' => new \Zend_Db_Expr('cs.store_id'), ] ); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php index c4eda1c987192..7a698ae595d19 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php @@ -1,6 +1,6 @@ $ifNullSql, + 'pid.entity_id', ] )->where( 'pid.attribute_id IN(?)', @@ -200,7 +201,7 @@ protected function _prepareSelectIndex($entityIds = null, $attributeId = null) 'select' => $select, 'entity_field' => new \Zend_Db_Expr('pid.entity_id'), 'website_field' => new \Zend_Db_Expr('pid.website_id'), - 'store_field' => new \Zend_Db_Expr('pid.store_id') + 'store_field' => new \Zend_Db_Expr('pid.store_id'), ] ); $query = $select->insertFromSelect($idxTable); @@ -221,11 +222,7 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu $connection = $this->getConnection(); // prepare multiselect attributes - if ($attributeId === null) { - $attrIds = $this->_getIndexableAttributes(true); - } else { - $attrIds = [$attributeId]; - } + $attrIds = $attributeId === null ? $this->_getIndexableAttributes(true) : [$attributeId]; if (!$attrIds) { return $this; @@ -247,20 +244,20 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu $productValueExpression = $connection->getCheckSql('pvs.value_id > 0', 'pvs.value', 'pvd.value'); $select = $connection->select()->from( ['pvd' => $this->getTable('catalog_product_entity_varchar')], - [$productIdField, 'attribute_id'] + [] )->join( ['cs' => $this->getTable('store')], '', - ['store_id'] + [] )->joinLeft( ['pvs' => $this->getTable('catalog_product_entity_varchar')], "pvs.{$productIdField} = pvd.{$productIdField} AND pvs.attribute_id = pvd.attribute_id" . ' AND pvs.store_id=cs.store_id', - ['value' => $productValueExpression] + [] )->joinLeft( ['cpe' => $this->getTable('catalog_product_entity')], "cpe.{$productIdField} = pvd.{$productIdField}", - ['entity_id'] + [] )->where( 'pvd.store_id=?', $connection->getIfNullSql('pvs.store_id', \Magento\Store\Model\Store::DEFAULT_STORE_ID) @@ -272,6 +269,14 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu $attrIds )->where( 'cpe.entity_id IS NOT NULL' + )->columns( + [ + 'entity_id' => 'cpe.entity_id', + 'attribute_id' => 'attribute_id', + 'store_id' => 'cs.store_id', + 'value' => $productValueExpression, + 'source_id' => 'cpe.entity_id', + ] ); $statusCond = $connection->quoteInto('=?', ProductStatus::STATUS_ENABLED); @@ -289,30 +294,11 @@ protected function _prepareMultiselectIndex($entityIds = null, $attributeId = nu 'select' => $select, 'entity_field' => new \Zend_Db_Expr('cpe.entity_id'), 'website_field' => new \Zend_Db_Expr('cs.website_id'), - 'store_field' => new \Zend_Db_Expr('cs.store_id') + 'store_field' => new \Zend_Db_Expr('cs.store_id'), ] ); - $i = 0; - $data = []; - $query = $select->query(); - while ($row = $query->fetch()) { - $values = explode(',', $row['value']); - foreach ($values as $valueId) { - if (isset($options[$row['attribute_id']][$valueId])) { - $data[] = [$row['entity_id'], $row['attribute_id'], $row['store_id'], $valueId]; - $i++; - if ($i % 10000 == 0) { - $this->_saveIndexData($data); - $data = []; - } - } - } - } - - $this->_saveIndexData($data); - unset($options); - unset($data); + $this->saveDataFromSelect($select, $options); return $this; } @@ -331,7 +317,7 @@ protected function _saveIndexData(array $data) $connection = $this->getConnection(); $connection->insertArray( $this->getIdxTable(), - ['entity_id', 'attribute_id', 'store_id', 'value'], + ['entity_id', 'attribute_id', 'store_id', 'value', 'source_id'], $data ); return $this; @@ -348,4 +334,31 @@ public function getIdxTable($table = null) { return $this->tableStrategy->getTableName('catalog_product_index_eav'); } + + /** + * @param \Magento\Framework\DB\Select $select + * @param array $options + * @return void + */ + private function saveDataFromSelect(\Magento\Framework\DB\Select $select, array $options) + { + $i = 0; + $data = []; + $query = $select->query(); + while ($row = $query->fetch()) { + $values = explode(',', $row['value']); + foreach ($values as $valueId) { + if (isset($options[$row['attribute_id']][$valueId])) { + $data[] = [$row['entity_id'], $row['attribute_id'], $row['store_id'], $valueId, $row['source_id']]; + $i++; + if ($i % 10000 == 0) { + $this->_saveIndexData($data); + $data = []; + } + } + } + } + + $this->_saveIndexData($data); + } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php index ea72691ea0039..ffaf8a5d100d3 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/LinkedProductSelectBuilderByIndexPrice.php @@ -1,12 +1,13 @@ storeManager = $storeManager; $this->resource = $resourceConnection; $this->customerSession = $customerSession; $this->metadataPool = $metadataPool; + $this->baseSelectProcessor = (null !== $baseSelectProcessor) + ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class); } /** @@ -58,24 +68,27 @@ public function build($productId) $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $productTable = $this->resource->getTableName('catalog_product_entity'); - return [$this->resource->getConnection()->select() + $priceSelect = $this->resource->getConnection()->select() ->from(['parent' => $productTable], '') ->joinInner( ['link' => $this->resource->getTableName('catalog_product_relation')], "link.parent_id = parent.$linkField", [] )->joinInner( - ['child' => $productTable], - "child.entity_id = link.child_id", + [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable], + sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), ['entity_id'] )->joinInner( ['t' => $this->resource->getTableName('catalog_product_index_price')], - 't.entity_id = child.entity_id', + sprintf('t.entity_id = %s.entity_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), [] - )->where('parent.entity_id = ? ', $productId) + )->where('parent.entity_id = ?', $productId) ->where('t.website_id = ?', $this->storeManager->getStore()->getWebsiteId()) ->where('t.customer_group_id = ?', $this->customerSession->getCustomerGroupId()) ->order('t.min_price ' . Select::SQL_ASC) - ->limit(1)]; + ->limit(1); + $priceSelect = $this->baseSelectProcessor->process($priceSelect); + + return [$priceSelect]; } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php index 289445ae2daf0..fbf2ea6eadaa9 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/DefaultPrice.php @@ -1,6 +1,6 @@ $select, 'entity_field' => new \Zend_Db_Expr('e.entity_id'), 'website_field' => new \Zend_Db_Expr('cw.website_id'), - 'store_field' => new \Zend_Db_Expr('cs.store_id') + 'store_field' => new \Zend_Db_Expr('cs.store_id'), ] ); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php index ddaf7adef8c14..bacf79408ca6b 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Indexer/Price/Factory.php @@ -1,6 +1,6 @@ fetchOne($select, $bind); } + /** + * Check if product has links. + * + * @param int $parentId ID of product + * @return bool + */ + public function hasProductLinks($parentId) + { + $connection = $this->getConnection(); + $select = $connection->select()->from( + $this->getMainTable(), + ['count' => new \Zend_Db_Expr('COUNT(*)')] + )->where( + 'product_id = :product_id' + ) ; + + return $connection->fetchOne( + $select, + [ + 'product_id' => $parentId + ] + ) > 0; + } + /** * Save Product Links process * diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/Collection.php index 999d70d808102..da9a46c9e106d 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/Collection.php @@ -1,6 +1,6 @@ getMetadataPool()->getMetadata(ProductInterface::class)->getIdentifierField(); + $identifierField = $this->getProductEntityMetadata()->getIdentifierField(); $this->getSelect()->where("product_entity_table.$identifierField IN (?)", $products); $this->_hasLinkFilter = true; } @@ -279,7 +200,7 @@ protected function _joinLinks() $connection->quoteInto('links.link_type_id = ?', $this->_linkTypeId), ]; $joinType = 'join'; - $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField(); + $linkField = $this->getProductEntityMetadata()->getLinkField(); if ($this->getProduct() && $this->getProduct()->getId()) { $linkFieldId = $this->getProduct()->getData( $linkField @@ -422,19 +343,6 @@ public function addLinkAttributeToFilter($code, $condition) return $this; } - /** - * Get MetadataPool instance - * @return MetadataPool - * @deprecated - */ - private function getMetadataPool() - { - if (!$this->metadataPool) { - $this->metadataPool = ObjectManager::getInstance()->get(MetadataPool::class); - } - return $this->metadataPool; - } - /** * Join Product To Links * @return void @@ -442,11 +350,15 @@ private function getMetadataPool() private function joinProductsToLinks() { if ($this->_hasLinkFilter) { - $metaDataPool = $this->getMetadataPool()->getMetadata(ProductInterface::class); + $metaDataPool = $this->getProductEntityMetadata(); $linkField = $metaDataPool->getLinkField(); $entityTable = $metaDataPool->getEntityTable(); $this->getSelect() - ->join(['product_entity_table' => $entityTable], "links.product_id = product_entity_table.$linkField", []); + ->join( + ['product_entity_table' => $entityTable], + "links.product_id = product_entity_table.$linkField", + [] + ); } } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/SaveHandler.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/SaveHandler.php index ad987c6c8b4b3..24a7210d8ff12 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Link/SaveHandler.php @@ -1,6 +1,6 @@ storeManager = $storeManager; $this->resource = $resourceConnection; $this->eavConfig = $eavConfig; $this->catalogHelper = $catalogHelper; $this->metadataPool = $metadataPool; + $this->baseSelectProcessor = (null !== $baseSelectProcessor) + ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class); } /** @@ -74,18 +84,19 @@ public function build($productId) "link.parent_id = parent.$linkField", [] )->joinInner( - ['child' => $productTable], - "child.entity_id = link.child_id", + [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable], + sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS, $linkField), ['entity_id'] )->joinInner( ['t' => $priceAttribute->getBackendTable()], - "t.$linkField = child.$linkField", + sprintf('t.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), [] - )->where('parent.entity_id = ? ', $productId) + )->where('parent.entity_id = ?', $productId) ->where('t.attribute_id = ?', $priceAttribute->getAttributeId()) ->where('t.value IS NOT NULL') ->order('t.value ' . Select::SQL_ASC) ->limit(1); + $priceSelect = $this->baseSelectProcessor->process($priceSelect); $priceSelectDefault = clone $priceSelect; $priceSelectDefault->where('t.store_id = ?', Store::DEFAULT_STORE_ID); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php index 792a8f5b86d10..e202a6846edaf 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderBySpecialPrice.php @@ -1,15 +1,19 @@ storeManager = $storeManager; $this->resource = $resourceConnection; @@ -72,6 +83,8 @@ public function __construct( $this->dateTime = $dateTime; $this->localeDate = $localeDate; $this->metadataPool = $metadataPool; + $this->baseSelectProcessor = (null !== $baseSelectProcessor) + ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class); } /** @@ -95,12 +108,12 @@ public function build($productId) "link.parent_id = parent.$linkField", [] )->joinInner( - ['child' => $productTable], - "child.entity_id = link.child_id", + [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable], + sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), ['entity_id'] )->joinInner( ['t' => $specialPriceAttribute->getBackendTable()], - "t.$linkField = child.$linkField", + sprintf('t.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), [] )->joinLeft( ['special_from' => $specialPriceFromDate->getBackendTable()], @@ -116,7 +129,7 @@ public function build($productId) $specialPriceToDate->getAttributeId() ), '' - )->where('parent.entity_id = ? ', $productId) + )->where('parent.entity_id = ?', $productId) ->where('t.attribute_id = ?', $specialPriceAttribute->getAttributeId()) ->where('t.value IS NOT NULL') ->where( @@ -127,6 +140,7 @@ public function build($productId) $currentDate )->order('t.value ' . Select::SQL_ASC) ->limit(1); + $specialPrice = $this->baseSelectProcessor->process($specialPrice); $specialPriceDefault = clone $specialPrice; $specialPriceDefault->where('t.store_id = ?', Store::DEFAULT_STORE_ID); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php index d2d6d89c0a2a5..bd6f9ff198b2d 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderByTierPrice.php @@ -1,12 +1,12 @@ storeManager = $storeManager; $this->resource = $resourceConnection; $this->customerSession = $customerSession; $this->catalogHelper = $catalogHelper; $this->metadataPool = $metadataPool; + $this->baseSelectProcessor = (null !== $baseSelectProcessor) + ? $baseSelectProcessor : ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class); } /** @@ -77,18 +86,19 @@ public function build($productId) "link.parent_id = parent.$linkField", [] )->joinInner( - ['child' => $productTable], - "child.entity_id = link.child_id", + [BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS => $productTable], + sprintf('%s.entity_id = link.child_id', BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), ['entity_id'] )->joinInner( ['t' => $this->resource->getTableName('catalog_product_entity_tier_price')], - "t.$linkField = child.$linkField", + sprintf('t.%s = %s.%1$s', $linkField, BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS), [] - )->where('parent.entity_id = ? ', $productId) + )->where('parent.entity_id = ?', $productId) ->where('t.all_groups = 1 OR customer_group_id = ?', $this->customerSession->getCustomerGroupId()) ->where('t.qty = ?', 1) ->order('t.value ' . Select::SQL_ASC) ->limit(1); + $priceSelect = $this->baseSelectProcessor->process($priceSelect); $priceSelectDefault = clone $priceSelect; $priceSelectDefault->where('t.website_id = ?', self::DEFAULT_WEBSITE_ID); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderComposite.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderComposite.php index f3dc225685985..377a4d6429e54 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderComposite.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/LinkedProductSelectBuilderComposite.php @@ -1,6 +1,6 @@ getTable('catalog_product_option_title'); foreach ([\Magento\Store\Model\Store::DEFAULT_STORE_ID, $object->getStoreId()] as $storeId) { $existInCurrentStore = $this->getColFromOptionTable($titleTableName, (int)$object->getId(), (int)$storeId); - $existInDefaultStore = $this->getColFromOptionTable( - $titleTableName, - (int)$object->getId(), - \Magento\Store\Model\Store::DEFAULT_STORE_ID - ); + $existInDefaultStore = (int)$storeId == \Magento\Store\Model\Store::DEFAULT_STORE_ID ? + $existInCurrentStore : + $this->getColFromOptionTable( + $titleTableName, + (int)$object->getId(), + \Magento\Store\Model\Store::DEFAULT_STORE_ID + ); + if ($object->getTitle()) { + $isDeleteStoreTitle = (bool)$object->getData('is_delete_store_title'); if ($existInCurrentStore) { - if ($object->getStoreId() == $storeId) { + if ($isDeleteStoreTitle && (int)$storeId != \Magento\Store\Model\Store::DEFAULT_STORE_ID) { + $connection->delete($titleTableName, ['option_title_id = ?' => $existInCurrentStore]); + + } elseif ($object->getStoreId() == $storeId) { $data = $this->_prepareDataForTable( new \Magento\Framework\DataObject(['title' => $object->getTitle()]), $titleTableName @@ -270,8 +277,13 @@ protected function _saveValueTitles(\Magento\Framework\Model\AbstractModel $obje } } else { // we should insert record into not default store only of if it does not exist in default store - if (($storeId == \Magento\Store\Model\Store::DEFAULT_STORE_ID && !$existInDefaultStore) - || ($storeId != \Magento\Store\Model\Store::DEFAULT_STORE_ID && !$existInCurrentStore) + if ( + ($storeId == \Magento\Store\Model\Store::DEFAULT_STORE_ID && !$existInDefaultStore) || + ( + $storeId != \Magento\Store\Model\Store::DEFAULT_STORE_ID && + !$existInCurrentStore && + !$isDeleteStoreTitle + ) ) { $data = $this->_prepareDataForTable( new \Magento\Framework\DataObject( diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Collection.php index 2d50ead9d56d9..8f434995de9e8 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Collection.php @@ -1,12 +1,13 @@ _optionValueCollectionFactory = $optionValueCollectionFactory; $this->_storeManager = $storeManager; + $this->metadataPool = $metadataPool ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\EntityManager\MetadataPool::class); parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource); } @@ -248,7 +253,7 @@ protected function _initSelect() ['cpe' => $this->getTable('catalog_product_entity')], sprintf( 'cpe.%s = main_table.product_id', - $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField() + $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField() ), [] ); @@ -318,18 +323,6 @@ public function reset() return $this->_reset(); } - /** - * @return \Magento\Framework\EntityManager\MetadataPool - */ - private function getMetadataPool() - { - if (null === $this->metadataPool) { - $this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\EntityManager\MetadataPool::class); - } - return $this->metadataPool; - } - /** * @return JoinProcessorInterface */ diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php index 39a67f9722e18..2dad5d0a441ec 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value.php @@ -1,6 +1,6 @@ getTable('catalog_product_option_type_price'); + $formattedPrice = $this->getLocaleFormatter()->getNumber($object->getPrice()); - $price = (double)sprintf('%F', $object->getPrice()); + $price = (double)sprintf('%F', $formattedPrice); $priceType = $object->getPriceType(); if ($object->getPrice() && $priceType) { @@ -231,6 +237,11 @@ protected function _saveValueTitles(\Magento\Framework\Model\AbstractModel $obje ); $optionTypeId = $this->getConnection()->fetchOne($select); $existInCurrentStore = $this->getOptionIdFromOptionTable($titleTable, (int)$object->getId(), (int)$storeId); + + if ($storeId != \Magento\Store\Model\Store::DEFAULT_STORE_ID && $object->getData('is_delete_store_title')) { + $object->unsetData('title'); + } + if ($object->getTitle()) { if ($existInCurrentStore) { if ($storeId == $object->getStoreId()) { @@ -410,4 +421,19 @@ public function duplicate(\Magento\Catalog\Model\Product\Option\Value $object, $ return $object; } + + /** + * Get FormatInterface to convert price from string to number format + * + * @return \Magento\Framework\Locale\FormatInterface + * @deprecated + */ + private function getLocaleFormatter() + { + if ($this->localeFormat === null) { + $this->localeFormat = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Locale\FormatInterface::class); + } + return $this->localeFormat; + } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value/Collection.php index 0924808a7dcac..1f65ec334dee4 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Option/Value/Collection.php @@ -1,6 +1,6 @@ attributeResource = $attributeResource; + $this->attributeRepository = $attributeRepository; + $this->productIdLocator = $productIdLocator; + $this->metadataPool = $metadataPool; + } + + /** + * {@inheritdoc} + */ + public function get(array $skus) + { + $ids = $this->retrieveAffectedIds($skus); + $priceTable = $this->attributeResource->getTable($this->priceTable); + $dateTimeTable = $this->attributeResource->getTable($this->datetimeTable); + $linkField = $this->getEntityLinkField(); + $select = $this->attributeResource->getConnection() + ->select() + ->from( + $priceTable, + [ + 'value_id', + 'store_id', + $this->getEntityLinkField(), + 'value', + ] + ) + ->joinLeft( + $dateTimeTable . ' AS datetime_from', + $priceTable . '.' . $linkField . '=' . 'datetime_from.' . $linkField + . ' AND datetime_from.attribute_id=' . $this->getPriceFromAttributeId(), + 'value AS price_from' + ) + ->joinLeft( + $dateTimeTable . ' AS datetime_to', + $priceTable . '.' . $linkField . '=' . 'datetime_to.' . $linkField + . ' AND datetime_to.attribute_id=' . $this->getPriceToAttributeId(), + 'value AS price_to' + ) + ->where($priceTable . '.' . $linkField . ' IN (?)', $ids) + ->where($priceTable . '.attribute_id = ?', $this->getPriceAttributeId()); + + return $this->attributeResource->getConnection()->fetchAll($select); + } + + /** + * {@inheritdoc} + */ + public function update(array $prices) + { + $formattedPrices = []; + $formattedDates = []; + + /** @var \Magento\Catalog\Api\Data\SpecialPriceInterface $price */ + foreach ($prices as $price) { + $productIdsBySku = $this->productIdLocator->retrieveProductIdsBySkus([$price->getSku()]); + $ids = array_keys($productIdsBySku[$price->getSku()]); + foreach ($ids as $id) { + $formattedPrices[] = [ + 'store_id' => $price->getStoreId(), + $this->getEntityLinkField() => $id, + 'value' => $price->getPrice(), + 'attribute_id' => $this->getPriceAttributeId(), + ]; + if ($price->getPriceFrom()) { + $formattedDates[] = [ + 'store_id' => $price->getStoreId(), + $this->getEntityLinkField() => $id, + 'value' => $price->getPriceFrom(), + 'attribute_id' => $this->getPriceFromAttributeId(), + ]; + } + if ($price->getPriceTo()) { + $formattedDates[] = [ + 'store_id' => $price->getStoreId(), + $this->getEntityLinkField() => $id, + 'value' => $price->getPriceTo(), + 'attribute_id' => $this->getPriceToAttributeId(), + ]; + } + } + } + $connection = $this->attributeResource->getConnection(); + $connection->beginTransaction(); + + try { + $this->updateItems($formattedPrices, $this->priceTable); + $this->updateItems($formattedDates, $this->datetimeTable); + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw new \Magento\Framework\Exception\CouldNotSaveException( + __('Could not save Prices.'), + $e + ); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function delete(array $prices) + { + $skus = array_unique( + array_map(function ($price) { + return $price->getSku(); + }, $prices) + ); + $ids = $this->retrieveAffectedIds($skus); + $connection = $this->attributeResource->getConnection(); + $connection->beginTransaction(); + try { + foreach (array_chunk($ids, $this->itemsPerOperation) as $idsBunch) { + $this->attributeResource->getConnection()->delete( + $this->attributeResource->getTable($this->priceTable), + [ + 'attribute_id = ?' => $this->getPriceAttributeId(), + $this->getEntityLinkField() . ' IN (?)' => $idsBunch + ] + ); + } + foreach (array_chunk($ids, $this->itemsPerOperation) as $idsBunch) { + $this->attributeResource->getConnection()->delete( + $this->attributeResource->getTable($this->datetimeTable), + [ + 'attribute_id IN (?)' => [$this->getPriceFromAttributeId(), $this->getPriceToAttributeId()], + $this->getEntityLinkField() . ' IN (?)' => $idsBunch + ] + ); + } + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw new \Magento\Framework\Exception\CouldNotDeleteException( + __('Could not delete Prices'), + $e + ); + } + + return true; + } + + /** + * Get link field. + * + * @return string + */ + public function getEntityLinkField() + { + return $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) + ->getLinkField(); + } + + /** + * Update items in database. + * + * @param array $items + * @param string $table + * @return void + */ + private function updateItems(array $items, $table) + { + foreach (array_chunk($items, $this->itemsPerOperation) as $itemsBunch) { + $this->attributeResource->getConnection()->insertOnDuplicate( + $this->attributeResource->getTable($table), + $itemsBunch, + ['value'] + ); + } + } + + /** + * Get special price attribute ID. + * + * @return int + */ + private function getPriceAttributeId() + { + if (!$this->priceAttributeId) { + $this->priceAttributeId = $this->attributeRepository->get('special_price')->getAttributeId(); + } + + return $this->priceAttributeId; + } + + /** + * Get special price from attribute ID. + * + * @return int + */ + private function getPriceFromAttributeId() + { + if (!$this->priceFromAttributeId) { + $this->priceFromAttributeId = $this->attributeRepository->get('special_from_date')->getAttributeId(); + } + + return $this->priceFromAttributeId; + } + + /** + * Get special price to attribute ID. + * + * @return int + */ + private function getPriceToAttributeId() + { + if (!$this->priceToAttributeId) { + $this->priceToAttributeId = $this->attributeRepository->get('special_to_date')->getAttributeId(); + } + + return $this->priceToAttributeId; + } + + /** + * Retrieve IDs of products, that were affected during price update. + * + * @param array $skus + * @return array + */ + private function retrieveAffectedIds(array $skus) + { + $affectedIds = []; + + foreach ($this->productIdLocator->retrieveProductIdsBySkus($skus) as $productIds) { + $affectedIds = array_merge($affectedIds, array_keys($productIds)); + } + + return array_unique($affectedIds); + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Relation.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Relation.php index c057ff91e6944..013adfcb18f4a 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Relation.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Relation.php @@ -1,6 +1,6 @@ eavConfig = $eavConfig; + $this->metadataPool = $metadataPool; + $this->storeResolver = $storeResolver; + } + + /** + * @param Select $select + * @return Select + */ + public function process(Select $select) + { + $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); + $statusAttribute = $this->eavConfig->getAttribute(Product::ENTITY, ProductInterface::STATUS); + + $select->joinLeft( + ['status_global_attr' => $statusAttribute->getBackendTable()], + "status_global_attr.{$linkField} = " . self::PRODUCT_TABLE_ALIAS . ".{$linkField}" + . ' AND status_global_attr.attribute_id = ' . (int)$statusAttribute->getAttributeId() + . ' AND status_global_attr.store_id = ' . Store::DEFAULT_STORE_ID, + [] + ); + + $select->joinLeft( + ['status_attr' => $statusAttribute->getBackendTable()], + "status_attr.{$linkField} = " . self::PRODUCT_TABLE_ALIAS . ".{$linkField}" + . ' AND status_attr.attribute_id = ' . (int)$statusAttribute->getAttributeId() + . ' AND status_attr.store_id = ' . $this->storeResolver->getCurrentStoreId(), + [] + ); + + $select->where('IFNULL(status_attr.value, status_global_attr.value) = ?', Status::STATUS_ENABLED); + + return $select; + } +} diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Website.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Website.php index 69d58ddefb700..b355c9e6374bb 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Website.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Website.php @@ -1,6 +1,6 @@ resource = $appResource; } + /** + * Get instance of ScopePool + * + * @return \Magento\Framework\App\Config + * @deprecated + */ + private function getAppConfig() + { + if ($this->appConfig === null) { + $this->appConfig = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\App\Config::class + ); + } + return $this->appConfig; + } + /** * Check url rewrite suffix - whether we can support it * @@ -103,6 +124,24 @@ public function afterSave() return parent::afterSave(); } + /** + * {@inheritdoc} + */ + public function afterDeleteCommit() + { + if ($this->isValueChanged()) { + $this->updateSuffixForUrlRewrites(); + if ($this->isCategorySuffixChanged()) { + $this->cacheTypeList->invalidate([ + \Magento\Framework\App\Cache\Type\Block::TYPE_IDENTIFIER, + \Magento\Framework\App\Cache\Type\Collection::TYPE_IDENTIFIER + ]); + } + } + + return parent::afterDeleteCommit(); + } + /** * Check is category suffix changed * @@ -135,7 +174,12 @@ protected function updateSuffixForUrlRewrites() } $entities = $this->urlFinder->findAllByData($dataFilter); $oldSuffixPattern = '~' . preg_quote($this->getOldValue()) . '$~'; - $suffix = $this->getValue(); + if ($this->getValue() !== null) { + $suffix = $this->getValue(); + } else { + $this->getAppConfig()->clean(); + $suffix = $this->_config->getValue($this->getPath()); + } foreach ($entities as $urlRewrite) { $bind = $urlRewrite->getIsAutogenerated() ? [UrlRewrite::REQUEST_PATH => preg_replace($oldSuffixPattern, $suffix, $urlRewrite->getRequestPath())] diff --git a/app/code/Magento/Catalog/Model/System/Config/Source/Inputtype.php b/app/code/Magento/Catalog/Model/System/Config/Source/Inputtype.php index 6202ffc1a4b51..d4cc7488d9235 100644 --- a/app/code/Magento/Catalog/Model/System/Config/Source/Inputtype.php +++ b/app/code/Magento/Catalog/Model/System/Config/Source/Inputtype.php @@ -1,6 +1,6 @@ mediaConfig = $mediaConfig; + $this->context = $context; + $this->filePath = $filePath; + $this->miscParams = $miscParams; + $this->encryptor = $encryptor; + } + + /** + * {@inheritdoc} + */ + public function getUrl() + { + return $this->context->getBaseUrl() . $this->getRelativePath(DIRECTORY_SEPARATOR); + } + + /** + * {@inheritdoc} + */ + public function getContentType() + { + return $this->contentType; + } + + /** + * {@inheritdoc} + */ + public function getPath() + { + return $this->getRelativePath($this->context->getPath()); + } + + /** + * Subroutine for building path + * + * @param string $path + * @param string $item + * @return string + */ + private function join($path, $item) + { + return trim( + $path . ($item ? DIRECTORY_SEPARATOR . ltrim($item, DIRECTORY_SEPARATOR) : ''), + DIRECTORY_SEPARATOR + ); + } + + /** + * {@inheritdoc} + */ + public function getSourceFile() + { + return $this->mediaConfig->getBaseMediaPath() + . DIRECTORY_SEPARATOR . ltrim($this->filePath, DIRECTORY_SEPARATOR); + } + + /** + * Get source content type + * + * @return string + */ + public function getSourceContentType() + { + return $this->contentType; + } + + /** + * {@inheritdoc} + */ + public function getContent() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getFilePath() + { + return $this->filePath; + } + + /** + * {@inheritdoc} + * @return ContextInterface + */ + public function getContext() + { + return $this->context; + } + + /** + * {@inheritdoc} + */ + public function getModule() + { + return 'cache'; + } + + /** + * Retrieve part of path based on misc params + * + * @return string + */ + private function getMiscPath() + { + return $this->encryptor->hash(implode('_', $this->miscParams), Encryptor::HASH_VERSION_MD5); + } + + /** + * Generate relative path + * + * @param string $result + * @return string + */ + private function getRelativePath($result) + { + $result = $this->join($result, $this->getModule()); + $result = $this->join($result, $this->getMiscPath()); + $result = $this->join($result, $this->getFilePath()); + return DIRECTORY_SEPARATOR . $result; + } +} diff --git a/app/code/Magento/Catalog/Model/View/Asset/Image/Context.php b/app/code/Magento/Catalog/Model/View/Asset/Image/Context.php new file mode 100644 index 0000000000000..f72447c6ca2c2 --- /dev/null +++ b/app/code/Magento/Catalog/Model/View/Asset/Image/Context.php @@ -0,0 +1,59 @@ +mediaConfig = $mediaConfig; + $this->filesystem = $filesystem; + $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->mediaDirectory->create($this->mediaConfig->getBaseMediaPath()); + } + + /** + * {@inheritdoc} + */ + public function getPath() + { + return $this->mediaDirectory->getAbsolutePath($this->mediaConfig->getBaseMediaPath()); + } + + /** + * {@inheritdoc} + */ + public function getBaseUrl() + { + return $this->mediaConfig->getBaseMediaUrl(); + } +} diff --git a/app/code/Magento/Catalog/Model/View/Asset/Placeholder.php b/app/code/Magento/Catalog/Model/View/Asset/Placeholder.php new file mode 100644 index 0000000000000..7fa55b27a4b99 --- /dev/null +++ b/app/code/Magento/Catalog/Model/View/Asset/Placeholder.php @@ -0,0 +1,181 @@ +context = $context; + $this->scopeConfig = $scopeConfig; + $this->assetRepo = $assetRepo; + $this->type = $type; + } + + /** + * {@inheritdoc} + */ + public function getUrl() + { + if ($this->getFilePath() !== null) { + $result = $this->context->getBaseUrl() . '/' . $this->getModule() . '/' . $this->getFilePath(); + } else { + $result = $this->assetRepo->getUrl("Magento_Catalog::images/product/placeholder/{$this->type}.jpg"); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function getContentType() + { + return $this->contentType; + } + + /** + * {@inheritdoc} + */ + public function getPath() + { + if ($this->getFilePath() !== null) { + $result = $this->getContext()->getPath() + . DIRECTORY_SEPARATOR . $this->getModule() + . DIRECTORY_SEPARATOR . $this->getFilePath(); + } else { + $defaultPlaceholder = $this->assetRepo->createAsset( + "Magento_Catalog::images/product/placeholder/{$this->type}.jpg" + ); + try { + $result = $defaultPlaceholder->getSourceFile(); + } catch (NotFoundException $e) { + $result = null; + } + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function getSourceFile() + { + return $this->getPath(); + } + + /** + * Get source content type + * + * @return string + */ + public function getSourceContentType() + { + return $this->contentType; + } + + /** + * {@inheritdoc} + */ + public function getContent() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function getFilePath() + { + if ($this->filePath !== null) { + return $this->filePath; + } + // check if placeholder defined in config + $isConfigPlaceholder = $this->scopeConfig->getValue( + "catalog/placeholder/{$this->type}_placeholder", + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + $this->filePath = $isConfigPlaceholder; + + return $this->filePath; + } + + /** + * {@inheritdoc} + * @return ContextInterface + */ + public function getContext() + { + return $this->context; + } + + /** + * {@inheritdoc} + */ + public function getModule() + { + return 'placeholder'; + } +} diff --git a/app/code/Magento/Catalog/Model/Webapi/Product/Option/Type/Date.php b/app/code/Magento/Catalog/Model/Webapi/Product/Option/Type/Date.php index 779c725bd909e..aeeaf049556d4 100644 --- a/app/code/Magento/Catalog/Model/Webapi/Product/Option/Type/Date.php +++ b/app/code/Magento/Catalog/Model/Webapi/Product/Option/Type/Date.php @@ -1,6 +1,6 @@ config = $config; + $this->productAttributeRepository = $productAttributeRepository; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + } + + /** + * Change scope for all price attributes according to + * 'Catalog Price Scope' configuration parameter value + * + * @param EventObserver $observer + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function execute(EventObserver $observer) + { + $this->searchCriteriaBuilder->addFilter('frontend_input', 'price'); + $criteria = $this->searchCriteriaBuilder->create(); + + $scope = $this->config->getValue(Store::XML_PATH_PRICE_SCOPE); + $scope = ($scope == Store::PRICE_SCOPE_WEBSITE) + ? ProductAttributeInterface::SCOPE_WEBSITE_TEXT + : ProductAttributeInterface::SCOPE_GLOBAL_TEXT; + + $priceAttributes = $this->productAttributeRepository->getList($criteria)->getItems(); + + /** @var ProductAttributeInterface $priceAttribute */ + foreach ($priceAttributes as $priceAttribute) { + $priceAttribute->setScope($scope); + $this->productAttributeRepository->save($priceAttribute); + } + } +} diff --git a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php index 72bf4468080e3..04b2dadf3b6f4 100644 --- a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php +++ b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php @@ -1,6 +1,6 @@ cache = $cache; $this->isCacheEnabled = $cacheState->isEnabled(\Magento\Eav\Model\Cache\Type::TYPE_IDENTIFIER); + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -43,12 +54,12 @@ public function aroundGetAttributesUsedInListing( ) { $cacheId = self::PRODUCT_LISTING_ATTRIBUTES_CACHE_ID . $config->getEntityTypeId() . '_' . $config->getStoreId(); if ($this->isCacheEnabled && ($attributes = $this->cache->load($cacheId))) { - return unserialize($attributes); + return $this->serializer->unserialize($attributes); } $attributes = $proceed(); if ($this->isCacheEnabled) { $this->cache->save( - serialize($attributes), + $this->serializer->serialize($attributes), $cacheId, [ \Magento\Eav\Model\Cache\Type::CACHE_TAG, @@ -71,12 +82,12 @@ public function aroundGetAttributesUsedForSortBy( $cacheId = self::PRODUCT_LISTING_SORT_BY_ATTRIBUTES_CACHE_ID . $config->getEntityTypeId() . '_' . $config->getStoreId(); if ($this->isCacheEnabled && ($attributes = $this->cache->load($cacheId))) { - return unserialize($attributes); + return $this->serializer->unserialize($attributes); } $attributes = $proceed(); if ($this->isCacheEnabled) { $this->cache->save( - serialize($attributes), + $this->serializer->serialize($attributes), $cacheId, [ \Magento\Eav\Model\Cache\Type::CACHE_TAG, diff --git a/app/code/Magento/Catalog/Pricing/Price/BasePrice.php b/app/code/Magento/Catalog/Pricing/Price/BasePrice.php index b32d3f14517c8..82bee56cd9ef8 100644 --- a/app/code/Magento/Catalog/Pricing/Price/BasePrice.php +++ b/app/code/Magento/Catalog/Pricing/Price/BasePrice.php @@ -1,6 +1,6 @@ calculator = $calculator; + } + + /** + * Get raw value of "as low as" as a minimal among tier prices + * {@inheritdoc} + */ + public function getValue(SaleableInterface $saleableItem) + { + /** @var TierPrice $price */ + $price = $saleableItem->getPriceInfo()->getPrice(TierPrice::PRICE_CODE); + $tierPriceList = $price->getTierPriceList(); + + $tierPrices = []; + foreach ($tierPriceList as $tierPrice) { + /** @var AmountInterface $price */ + $price = $tierPrice['price']; + $tierPrices[] = $price->getValue(); + } + + return $tierPrices ? min($tierPrices) : null; + } + + /** + * Return calculated amount object that keeps "as low as" value + * {@inheritdoc} + */ + public function getAmount(SaleableInterface $saleableItem) + { + $value = $this->getValue($saleableItem); + + return $value === null + ? null + : $this->calculator->getAmount($value, $saleableItem); + } +} diff --git a/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php b/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php index bac187bb820fe..4187a9a208b09 100644 --- a/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php +++ b/app/code/Magento/Catalog/Pricing/Price/RegularPrice.php @@ -1,6 +1,6 @@ salableResolver = $salableResolver ?: ObjectManager::getInstance()->get(SalableResolverInterface::class); + $this->minimalPriceCalculator = $minimalPriceCalculator + ?: ObjectManager::getInstance()->get(MinimalPriceCalculatorInterface::class); + } + /** * @return string */ protected function _toHtml() { - if (!$this->getSaleableItem() || $this->getSaleableItem()->getCanShowPrice() === false) { + if (!$this->salableResolver->isSalable($this->getSaleableItem())) { return ''; } $result = parent::_toHtml(); - - try { - /** @var MsrpPrice $msrpPriceType */ - $msrpPriceType = $this->getSaleableItem()->getPriceInfo()->getPrice('msrp_price'); - } catch (\InvalidArgumentException $e) { - $this->_logger->critical($e); - return $this->wrapResult($result); - } - //Renders MSRP in case it is enabled - $product = $this->getSaleableItem(); - if ($msrpPriceType->canApplyMsrp($product) && $msrpPriceType->isMinimalPriceLessMsrp($product)) { + if ($this->isMsrpPriceApplicable()) { /** @var BasePriceBox $msrpBlock */ $msrpBlock = $this->rendererPool->createPriceRender( MsrpPrice::PRICE_CODE, @@ -56,6 +86,25 @@ protected function _toHtml() return $this->wrapResult($result); } + /** + * Check is MSRP applicable for the current product. + * + * @return bool + */ + protected function isMsrpPriceApplicable() + { + try { + /** @var MsrpPrice $msrpPriceType */ + $msrpPriceType = $this->getSaleableItem()->getPriceInfo()->getPrice('msrp_price'); + } catch (\InvalidArgumentException $e) { + $this->_logger->critical($e); + return false; + } + + $product = $this->getSaleableItem(); + return $msrpPriceType->canApplyMsrp($product) && $msrpPriceType->isMinimalPriceLessMsrp($product); + } + /** * Wrap with standard required container * @@ -77,11 +126,15 @@ protected function wrapResult($html) */ public function renderAmountMinimal() { - /** @var \Magento\Catalog\Pricing\Price\FinalPrice $price */ - $price = $this->getPriceType(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE); $id = $this->getPriceId() ? $this->getPriceId() : 'product-minimal-price-' . $this->getSaleableItem()->getId(); + + $amount = $this->minimalPriceCalculator->getAmount($this->getSaleableItem()); + if ($amount === null) { + return ''; + } + return $this->renderAmount( - $price->getMinimalPrice(), + $amount, [ 'display_label' => __('As low as'), 'price_id' => $id, @@ -110,13 +163,15 @@ public function hasSpecialPrice() */ public function showMinimalPrice() { + $minTierPrice = $this->minimalPriceCalculator->getValue($this->getSaleableItem()); + /** @var Price\FinalPrice $finalPrice */ $finalPrice = $this->getPriceType(Price\FinalPrice::PRICE_CODE); $finalPriceValue = $finalPrice->getAmount()->getValue(); - $minimalPriceAValue = $finalPrice->getMinimalPrice()->getValue(); + return $this->getDisplayMinimalPrice() - && $minimalPriceAValue - && $minimalPriceAValue < $finalPriceValue; + && $minTierPrice !== null + && $minTierPrice < $finalPriceValue; } /** diff --git a/app/code/Magento/Catalog/Pricing/Render/PriceBox.php b/app/code/Magento/Catalog/Pricing/Render/PriceBox.php index 92ff22decb1d0..156fbb8633699 100644 --- a/app/code/Magento/Catalog/Pricing/Render/PriceBox.php +++ b/app/code/Magento/Catalog/Pricing/Render/PriceBox.php @@ -1,6 +1,6 @@ getConnection() ->createTable($table); + $customerGroupTable = $setup->getConnection()->describeTable($setup->getTable('customer_group')); + $customerGroupIdType = $customerGroupTable['customer_group_id']['DATA_TYPE'] == 'int' + ? \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER : $customerGroupTable['customer_group_id']['DATA_TYPE']; /** * Create table 'catalog_product_entity_tier_price' */ @@ -1883,7 +1887,7 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con ) ->addColumn( 'customer_group_id', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, + $customerGroupIdType, null, ['unsigned' => true, 'nullable' => false, 'default' => '0'], 'Customer Group ID' @@ -2426,7 +2430,6 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con 'option_id', $installer->getTable('catalog_product_option'), 'option_id', - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE, \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE ) ->setComment( @@ -2937,7 +2940,7 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con ) ->addColumn( 'customer_group_id', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, + $customerGroupIdType, null, ['unsigned' => true, 'nullable' => false, 'primary' => true], 'Customer Group ID' @@ -3056,7 +3059,7 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con ) ->addColumn( 'customer_group_id', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, + $customerGroupIdType, null, ['unsigned' => true, 'nullable' => false, 'primary' => true], 'Customer Group ID' diff --git a/app/code/Magento/Catalog/Setup/Recurring.php b/app/code/Magento/Catalog/Setup/Recurring.php index 85484cdddb218..e6cb302747918 100644 --- a/app/code/Magento/Catalog/Setup/Recurring.php +++ b/app/code/Magento/Catalog/Setup/Recurring.php @@ -1,6 +1,6 @@ getVersion(), '2.0.7') < 0) { - /** @var EavSetup $eavSetupF */ + /** @var EavSetup $eavSetup */ $eavSetup= $this->eavSetupFactory->create(['setup' => $setup]); $eavSetup->updateAttribute( @@ -353,7 +353,32 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface ] ); } - + + if (version_compare($context->getVersion(), '2.1.3') < 0) { + /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); + $this->changePriceAttributeDefaultScope($categorySetup); + } + $setup->endSetup(); } + + /** + * @param \Magento\Catalog\Setup\CategorySetup $categorySetup + * @return void + */ + private function changePriceAttributeDefaultScope($categorySetup) + { + $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); + foreach (['price', 'cost', 'special_price'] as $attributeCode) { + $attribute = $categorySetup->getAttribute($entityTypeId, $attributeCode); + $categorySetup->updateAttribute( + $entityTypeId, + $attribute['attribute_id'], + 'is_global', + \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL + ); + + } + } } diff --git a/app/code/Magento/Catalog/Setup/UpgradeSchema.php b/app/code/Magento/Catalog/Setup/UpgradeSchema.php old mode 100644 new mode 100755 index 03f3ac9581729..1be49fc30e4ef --- a/app/code/Magento/Catalog/Setup/UpgradeSchema.php +++ b/app/code/Magento/Catalog/Setup/UpgradeSchema.php @@ -1,6 +1,6 @@ getVersion(), '2.0.6', '<')) { $this->addUniqueKeyToCategoryProductTable($setup); } + + if (version_compare($context->getVersion(), '2.1.0', '<')) { + $this->addPercentageValueColumn($setup); + } + + if (version_compare($context->getVersion(), '2.1.1', '<')) { + $tables = [ + 'catalog_product_index_price_cfg_opt_agr_idx', + 'catalog_product_index_price_cfg_opt_agr_tmp', + 'catalog_product_index_price_cfg_opt_idx', + 'catalog_product_index_price_cfg_opt_tmp', + 'catalog_product_index_price_final_idx', + 'catalog_product_index_price_final_tmp', + 'catalog_product_index_price_idx', + 'catalog_product_index_price_opt_agr_idx', + 'catalog_product_index_price_opt_agr_tmp', + 'catalog_product_index_price_opt_idx', + 'catalog_product_index_price_opt_tmp', + 'catalog_product_index_price_tmp', + ]; + foreach ($tables as $table) { + $setup->getConnection()->modifyColumn( + $setup->getTable($table), + 'customer_group_id', + ['type' => 'integer', 'nullable' => false] + ); + } + } + + if (version_compare($context->getVersion(), '2.1.2', '<')) { + $this->addSourceEntityIdToProductEavIndex($setup); + } + + if (version_compare($context->getVersion(), '2.1.4', '<')) { + $this->recreateCatalogCategoryProductIndexTmpTable($setup); + } + $setup->endSetup(); } + /** + * Add the column 'source_id' to the Product EAV index tables. + * It allows to identify which entity was used to create value in the index. + * It is useful to identify original entity in a composite products. + * + * @param SchemaSetupInterface $setup + * @return void + */ + private function addSourceEntityIdToProductEavIndex(SchemaSetupInterface $setup) + { + $tables = [ + 'catalog_product_index_eav', + 'catalog_product_index_eav_idx', + 'catalog_product_index_eav_tmp', + 'catalog_product_index_eav_decimal', + 'catalog_product_index_eav_decimal_idx', + 'catalog_product_index_eav_decimal_tmp', + ]; + $connection = $setup->getConnection(); + foreach ($tables as $tableName) { + $tableName = $setup->getTable($tableName); + $connection->addColumn( + $tableName, + 'source_id', + [ + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + 'unsigned' => true, + 'nullable' => false, + 'default' => 0, + 'comment' => 'Original entity Id for attribute value', + ] + ); + $connection->dropIndex($tableName, $connection->getPrimaryKeyName($tableName)); + $primaryKeyFields = ['entity_id', 'attribute_id', 'store_id', 'value', 'source_id']; + $setup->getConnection()->addIndex( + $tableName, + $connection->getIndexName($tableName, $primaryKeyFields), + $primaryKeyFields, + \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_PRIMARY + ); + } + } + /** * @param SchemaSetupInterface $setup * @return void @@ -278,4 +358,95 @@ private function removeGroupPrice(SchemaSetupInterface $setup) $connection->dropColumn($setup->getTable($filedInfo['table']), $filedInfo['column']); } } + + /** + * Add percentage value column + * @param SchemaSetupInterface $setup + * @return void + */ + private function addPercentageValueColumn(SchemaSetupInterface $setup) + { + $connection = $setup->getConnection(); + $connection->addColumn( + $setup->getTable('catalog_product_entity_tier_price'), + 'percentage_value', + [ + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL, + 'nullable' => true, + 'length' => '5,2', + 'comment' => 'Percentage value', + 'after' => 'value' + ] + ); + } + + /** + * Drop and recreate catalog_category_product_index_tmp table + * + * Before this update the catalog_category_product_index_tmp table was created without usage of PK + * and with engine=MEMORY. Such structure of catalog_category_product_index_tmp table causes + * issues with MySQL DB replication. + * + * To avoid replication issues this method drops catalog_category_product_index_tmp table + * and creates new one with PK and engine=InnoDB + * + * @param SchemaSetupInterface $setup + * @return void + */ + private function recreateCatalogCategoryProductIndexTmpTable(SchemaSetupInterface $setup) + { + $tableName = $setup->getTable('catalog_category_product_index_tmp'); + + // Drop catalog_category_product_index_tmp table + $setup->getConnection()->dropTable($tableName); + + // Create catalog_category_product_index_tmp table with PK and engine=InnoDB + $table = $setup->getConnection() + ->newTable($tableName) + ->addColumn( + 'category_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'], + 'Category ID' + ) + ->addColumn( + 'product_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'], + 'Product ID' + ) + ->addColumn( + 'position', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['nullable' => false, 'default' => '0'], + 'Position' + ) + ->addColumn( + 'is_parent', + \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, + null, + ['unsigned' => true, 'nullable' => false, 'default' => '0'], + 'Is Parent' + ) + ->addColumn( + 'store_id', + \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, + null, + ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'], + 'Store ID' + ) + ->addColumn( + 'visibility', + \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, + null, + ['unsigned' => true, 'nullable' => false], + 'Visibility' + ) + ->setComment('Catalog Category Product Indexer temporary table'); + + $setup->getConnection()->createTable($table); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Category/AbstractCategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Category/AbstractCategoryTest.php index cb7d1c20b3356..f22f7f50859a2 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Category/AbstractCategoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Category/AbstractCategoryTest.php @@ -1,6 +1,6 @@ imageHelper = $this->getMockBuilder(\Magento\Catalog\Helper\Image::class) ->disableOriginalConstructor() - ->setMethods(['getDefaultPlaceholderUrl', 'getPlaceholder']) - ->getMock(); - - $this->assetRepo = $this->getMockBuilder(\Magento\Framework\View\Asset\Repository::class) - ->disableOriginalConstructor() - ->setMethods(['createAsset', 'getPath']) + ->setMethods(['getDefaultPlaceholderUrl']) ->getMock(); $this->objectManager->setBackwardCompatibleProperty( @@ -185,16 +175,8 @@ public function testGetImagesJsonWithException() $this->imageHelper ); - $this->objectManager->setBackwardCompatibleProperty( - $this->content, - 'assetRepo', - $this->assetRepo - ); - $placeholderUrl = 'url_to_the_placeholder/placeholder.jpg'; - $sizePlaceholder = ['size' => 399659]; - $imagesResult = [ [ 'value_id' => '2', @@ -202,7 +184,7 @@ public function testGetImagesJsonWithException() 'media_type' => 'image', 'position' => '0', 'url' => 'url_to_the_placeholder/placeholder.jpg', - 'size' => 399659 + 'size' => 0 ], [ 'value_id' => '1', @@ -210,7 +192,7 @@ public function testGetImagesJsonWithException() 'media_type' => 'image', 'position' => '1', 'url' => 'url_to_the_placeholder/placeholder.jpg', - 'size' => 399659 + 'size' => 0 ] ]; @@ -238,18 +220,13 @@ public function testGetImagesJsonWithException() $this->mediaConfigMock->expects($this->any())->method('getMediaPath'); $this->readMock->expects($this->any())->method('stat')->willReturnOnConsecutiveCalls( $this->throwException( - new \Magento\Framework\Exception\FileSystemException(new \Magento\Framework\Phrase('test')) + new \Magento\Framework\Exception\FileSystemException(new Phrase('test')) ), - $sizePlaceholder, $this->throwException( - new \Magento\Framework\Exception\FileSystemException(new \Magento\Framework\Phrase('test')) - ), - $sizePlaceholder + new \Magento\Framework\Exception\FileSystemException(new Phrase('test')) + ) ); $this->imageHelper->expects($this->any())->method('getDefaultPlaceholderUrl')->willReturn($placeholderUrl); - $this->imageHelper->expects($this->any())->method('getPlaceholder'); - $this->assetRepo->expects($this->any())->method('createAsset')->willReturnSelf(); - $this->assetRepo->expects($this->any())->method('getPath'); $this->jsonEncoderMock->expects($this->once())->method('encode')->willReturnCallback('json_encode'); $this->assertSame(json_encode($imagesResult), $this->content->getImagesJson()); diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/GalleryTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/GalleryTest.php index 03e6c36a14aa0..19814f95694b7 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/GalleryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Product/Helper/Form/GalleryTest.php @@ -1,6 +1,6 @@ disableOriginalConstructor() ->setMethods(['dispatch']) ->getMock(); - $eventManager->expects($this->once())->method('dispatch')->will($this->returnValue(true)); - - $scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config::class) - ->setMethods(['getValue']) - ->disableOriginalConstructor()->getMock(); - $scopeConfig->expects($this->once())->method('getValue')->withAnyParameters() - ->will($this->returnValue(false)); + $eventManager->expects($this->exactly(2))->method('dispatch')->will($this->returnValue(true)); $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)->disableOriginalConstructor() ->setMethods(['setStoreId', 'load', 'getId', '__wakeup', '__sleep']) @@ -93,8 +87,6 @@ public function testToHtml() $this->context->expects($this->once())->method('getEventManager') ->will($this->returnValue($eventManager)); - $this->context->expects($this->once())->method('getScopeConfig') - ->will($this->returnValue($scopeConfig)); $this->context->expects($this->once())->method('getLayout') ->will($this->returnValue($layout)); $this->context->expects($this->once())->method('getRequest') diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Rss/Grid/LinkTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Rss/Grid/LinkTest.php index 8bc6675933768..11efb045a1c2f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Rss/Grid/LinkTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Adminhtml/Rss/Grid/LinkTest.php @@ -1,6 +1,6 @@ productMock->expects($this->once()) ->method('getIdentities') @@ -154,9 +154,9 @@ public function testGetAddToCartPostParams() ]; $this->typeInstanceMock->expects($this->once()) - ->method('hasRequiredOptions') + ->method('isPossibleBuyFromList') ->with($this->equalTo($this->productMock)) - ->will($this->returnValue(false)); + ->will($this->returnValue(true)); $this->cartHelperMock->expects($this->any()) ->method('getAddUrl') ->with($this->equalTo($this->productMock), $this->equalTo([])) diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListTest.php index 786185e60e9db..de0e3d5f0d5ef 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ListTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ListTest.php @@ -1,6 +1,6 @@ method('init') ->willReturnMap([ [$productMock, 'product_page_image_small', [], $this->imageHelper], - [$productMock, 'product_page_image_medium', [], $this->imageHelper], - [$productMock, 'product_page_image_large', [], $this->imageHelper], + [$productMock, 'product_page_image_medium_no_frame', [], $this->imageHelper], + [$productMock, 'product_page_image_large_no_frame', [], $this->imageHelper], ]) ->willReturnSelf(); $this->imageHelper->expects($this->exactly(3)) @@ -129,19 +129,6 @@ public function testGetGalleryImages() ->method('getUrl') ->willReturn('product_page_image_large_url'); - $this->imageHelper->expects($this->exactly(2)) - ->method('constrainOnly') - ->with(true) - ->willReturnSelf(); - $this->imageHelper->expects($this->exactly(2)) - ->method('keepAspectRatio') - ->with(true) - ->willReturnSelf(); - $this->imageHelper->expects($this->exactly(2)) - ->method('keepFrame') - ->with(false) - ->willReturnSelf(); - $images = $this->model->getGalleryImages(); $this->assertInstanceOf(\Magento\Framework\Data\Collection::class, $images); } diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/View/OptionsTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/View/OptionsTest.php index 0e8d55232221a..9bafb60fc5b44 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/View/OptionsTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/View/OptionsTest.php @@ -1,6 +1,6 @@ productTypeConfig = $this->getMock(\Magento\Catalog\Model\ProductTypes\ConfigInterface::class); $this->registryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); - $this->view = $helper->getObject( + $this->view = $helper->getObject( \Magento\Catalog\Block\Product\View::class, ['productTypeConfig' => $this->productTypeConfig, 'registry' => $this->registryMock] ); @@ -65,7 +65,7 @@ public function testShouldRenderQuantity() public function testGetIdentities() { - $productTags = ['catalog_product_1']; + $productTags = ['cat_p_1']; $product = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); $category = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false); @@ -84,6 +84,6 @@ public function testGetIdentities() ] ) ); - $this->assertEquals(['catalog_product_1', 'catalog_category_1'], $this->view->getIdentities()); + $this->assertEquals(['cat_p_1', 'cat_c_1'], $this->view->getIdentities()); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/Widget/NewWidgetTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/Widget/NewWidgetTest.php index cfd009787158a..90d76e469b7ab 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/Widget/NewWidgetTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/Widget/NewWidgetTest.php @@ -1,6 +1,6 @@ scopeConfig = $this->getMock(\Magento\Framework\App\Config::class, ['getValue'], [], '', false, false); + $this->scopeConfig = $this->getMock(\Magento\Framework\App\Config::class, [], [], '', false, false); $this->cacheState = $this->getMock( \Magento\Framework\App\Cache\State::class, ['isEnabled'], @@ -186,10 +186,8 @@ public function testGetProductsCount() protected function generalGetProductCollection() { - $this->eventManager->expects($this->once())->method('dispatch') + $this->eventManager->expects($this->exactly(2))->method('dispatch') ->will($this->returnValue(true)); - $this->scopeConfig->expects($this->once())->method('getValue')->withAnyParameters() - ->willReturn(false); $this->cacheState->expects($this->atLeastOnce())->method('isEnabled')->withAnyParameters() ->willReturn(false); $this->catalogConfig->expects($this->once())->method('getProductAttributes') diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Rss/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Rss/CategoryTest.php index e7e8171868f94..7a58617b90d58 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Rss/CategoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Rss/CategoryTest.php @@ -1,6 +1,6 @@ appState->expects($this->once()) ->method('setAreaCode') - ->with('catalog') + ->with(Area::AREA_GLOBAL) ->willReturnSelf(); $this->productCollection->expects($this->once()) @@ -101,7 +102,7 @@ public function testExecute() $this->appState->expects($this->once()) ->method('setAreaCode') - ->with('catalog') + ->with(Area::AREA_GLOBAL) ->willReturnSelf(); $this->productCollection->expects($this->once()) @@ -142,7 +143,7 @@ public function testExecuteWithException() $this->appState->expects($this->once()) ->method('setAreaCode') - ->with('catalog') + ->with(Area::AREA_GLOBAL) ->willReturnSelf(); $this->productCollection->expects($this->once()) diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/DeleteTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/DeleteTest.php index 4a4c68b642669..282fb99a24d0a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/DeleteTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/DeleteTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + } + + public function executeDataProvider() + { + return [ + ['image1', 'image1'], + ['image2', 'image2'], + [null, 'image'], + ]; + } + + /** + * @param string $name + * @param string $savedName + * + * @dataProvider executeDataProvider + */ + public function testExecute($name, $savedName) + { + $request = $this->objectManager->getObject(Request::class); + + $uploader = $this->getMock(ImageUploader::class, ['saveFileToTmpDir'], [], '', false); + + $resultFactory = $this->getMock(ResultFactory::class, ['create'], [], '', false); + + $resultFactory->expects($this->once()) + ->method('create') + ->will($this->returnValue(new DataObject())); + + $model = $this->objectManager->getObject(Model::class, [ + 'request' => $request, + 'resultFactory' => $resultFactory, + 'imageUploader' => $uploader + ]); + + $uploader->expects($this->once()) + ->method('saveFileToTmpDir') + ->with($savedName) + ->will($this->returnValue([])); + + $request->setParam('param_name', $name); + + $model->execute(); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php index 51d99f7219575..6c6fa4c3a10ab 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php @@ -1,10 +1,12 @@ markTestSkipped('Due to MAGETWO-48956'); $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - - $this->contextMock = $this->getMock( - \Magento\Backend\App\Action\Context::class, - [ - 'getTitle', - 'getRequest', - 'getObjectManager', - 'getEventManager', - 'getResponse', - 'getMessageManager', - 'getResultRedirectFactory' - ], - [], - '', - false - ); $this->resultRedirectFactoryMock = $this->getMock( \Magento\Backend\Model\View\Result\RedirectFactory::class, ['create'], @@ -109,13 +74,6 @@ protected function setUp() '', false ); - $this->resultRawFactoryMock = $this->getMock( - \Magento\Framework\Controller\Result\RawFactory::class, - [], - [], - '', - false - ); $this->resultJsonFactoryMock = $this->getMock( \Magento\Framework\Controller\Result\JsonFactory::class, ['create'], @@ -151,12 +109,6 @@ protected function setUp() true, ['dispatch'] ); - $this->responseMock = $this->getMockForAbstractClass( - \Magento\Framework\App\ResponseInterface::class, - [], - '', - false - ); $this->messageManagerMock = $this->getMockForAbstractClass( \Magento\Framework\Message\ManagerInterface::class, [], @@ -167,23 +119,15 @@ protected function setUp() ['addSuccess', 'getMessages'] ); - $this->contextMock->expects($this->any())->method('getTitle')->willReturn($this->titleMock); - $this->contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->any())->method('getEventManager')->willReturn($this->eventManagerMock); - $this->contextMock->expects($this->any())->method('getResponse')->willReturn($this->responseMock); - $this->contextMock->expects($this->any())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->any()) - ->method('getResultRedirectFactory') - ->willReturn($this->resultRedirectFactoryMock); - $this->save = $this->objectManager->getObject( \Magento\Catalog\Controller\Adminhtml\Category\Save::class, [ - 'context' => $this->contextMock, - 'resultRawFactory' => $this->resultRawFactoryMock, + 'request' => $this->requestMock, + 'eventManager' => $this->eventManagerMock, + 'messageManager' => $this->messageManagerMock, 'resultJsonFactory' => $this->resultJsonFactoryMock, - 'layoutFactory' => $this->layoutFactoryMock + 'layoutFactory' => $this->layoutFactoryMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock ] ); } @@ -201,6 +145,8 @@ protected function setUp() */ public function testExecute($categoryId, $storeId, $parentId) { + $this->markTestSkipped('Due to MAGETWO-48956'); + $rootCategoryId = \Magento\Catalog\Model\Category::TREE_ROOT_ID; $products = [['any_product']]; $postData = [ @@ -577,4 +523,95 @@ public function dataProviderExecute() ] ]; } + + /** + * @return array + */ + public function imagePreprocessingDataProvider() + { + return [ + [['attribute1' => null, 'attribute2' => 123]], + [['attribute2' => 123]] + ]; + } + + /** + * @dataProvider imagePreprocessingDataProvider + * + * @param array $data + */ + public function testImagePreprocessingWithoutValue($data) + { + $eavConfig = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityType'], [], '', false); + + $imageBackendModel = $this->objectManager->getObject( + \Magento\Catalog\Model\Category\Attribute\Backend\Image::class + ); + + $collection = new \Magento\Framework\DataObject(['attribute_collection' => [ + new \Magento\Framework\DataObject([ + 'attribute_code' => 'attribute1', + 'backend' => $imageBackendModel + ]), + new \Magento\Framework\DataObject([ + 'attribute_code' => 'attribute2', + 'backend' => new \Magento\Framework\DataObject() + ]) + ]]); + + $eavConfig->expects($this->once()) + ->method('getEntityType') + ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE) + ->will($this->returnValue($collection)); + + $model = $this->objectManager->getObject(\Magento\Catalog\Controller\Adminhtml\Category\Save::class, [ + 'eavConfig' => $eavConfig + ]); + + $result = $model->imagePreprocessing($data); + + $this->assertEquals([ + 'attribute1' => false, + 'attribute2' => 123 + ], $result); + } + + public function testImagePreprocessingWithValue() + { + $eavConfig = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityType'], [], '', false); + + $imageBackendModel = $this->objectManager->getObject( + \Magento\Catalog\Model\Category\Attribute\Backend\Image::class + ); + + $collection = new \Magento\Framework\DataObject(['attribute_collection' => [ + new \Magento\Framework\DataObject([ + 'attribute_code' => 'attribute1', + 'backend' => $imageBackendModel + ]), + new \Magento\Framework\DataObject([ + 'attribute_code' => 'attribute2', + 'backend' => new \Magento\Framework\DataObject() + ]) + ]]); + + $eavConfig->expects($this->once()) + ->method('getEntityType') + ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE) + ->will($this->returnValue($collection)); + + $model = $this->objectManager->getObject(Model::class, [ + 'eavConfig' => $eavConfig + ]); + + $result = $model->imagePreprocessing([ + 'attribute1' => 'somevalue', + 'attribute2' => null + ]); + + $this->assertEquals([ + 'attribute1' => 'somevalue', + 'attribute2' => null + ], $result); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Widget/CategoriesJsonTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Widget/CategoriesJsonTest.php index 824d1c7bf23f2..59b2238aacdbc 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Widget/CategoriesJsonTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Widget/CategoriesJsonTest.php @@ -1,7 +1,7 @@ objectManager = new ObjectManager($this); + $this->contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productBuilderMock = $this->getMockBuilder(ProductBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultJsonFactoryMock = $this->getMockBuilder(JsonFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->setMethods(['getParam', 'setParam']) + ->getMockForAbstractClass(); + $this->contextMock->expects($this->once()) + ->method('getRequest') + ->willReturn($this->requestMock); + $this->attributeSetRepositoryMock = $this->getMockBuilder(AttributeSetRepositoryInterface::class) + ->setMethods(['get']) + ->getMockForAbstractClass(); + $this->attributeSetInterfaceMock = $this->getMockBuilder(AttributeSetInterface::class) + ->getMockForAbstractClass(); + $this->searchCriteriaBuilderMock = $this->getMockBuilder(SearchCriteriaBuilder::class) + ->disableOriginalConstructor() + ->setMethods(['addFilter', 'create', 'setPageSize']) + ->getMockForAbstractClass(); + $this->searchCriteriaMock = $this->getMockBuilder(SearchCriteria::class) + ->disableOriginalConstructor() + ->getMock(); + $this->attributeGroupRepositoryMock = $this->getMockBuilder(AttributeGroupRepositoryInterface::class) + ->setMethods(['getList']) + ->getMockForAbstractClass(); + $this->attributeGroupSearchResultsMock = $this->getMockBuilder(AttributeGroupSearchResultsInterface::class) + ->setMethods(['getItems']) + ->getMockForAbstractClass(); + $this->attributeGroupInterfaceFactoryMock = $this->getMockBuilder(AttributeGroupInterfaceFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->attributeGroupInterfaceMock = $this->getMockBuilder(AttributeGroupInterface::class) + ->setMethods(['getExtensionAttributes']) + ->getMockForAbstractClass(); + $this->jsonMock = $this->getMockBuilder(Json::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->controller = $this->objectManager->getObject( + AddAttributeToTemplate::class, + [ + 'context' => $this->contextMock, + 'productBuilder' => $this->productBuilderMock, + 'resultJsonFactory' => $this->resultJsonFactoryMock, + ] + ); + + $this->objectManager->setBackwardCompatibleProperty( + $this->controller, + 'attributeSetRepository', + $this->attributeSetRepositoryMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->controller, + 'searchCriteriaBuilder', + $this->searchCriteriaBuilderMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->controller, + 'attributeGroupRepository', + $this->attributeGroupRepositoryMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->controller, + 'attributeGroupFactory', + $this->attributeGroupInterfaceFactoryMock + ); + } + + public function testExecuteWithoutAttributeGroupItems() + { + $groupCode = 'attributes'; + $groupName = 'Attributes'; + $groupSortOrder = '15'; + $templateId = '4'; + $attributeIds = [ + 'selected' => ["178"], + 'total' => '1' + ]; + + $this->requestMock + ->expects($this->any()) + ->method('getParam') + ->willReturnMap( + [ + ['groupCode', null, $groupCode], + ['groupName', null, $groupName], + ['groupSortOrder', null, $groupSortOrder], + ['templateId', null, $templateId], + ['attributeIds', [], $attributeIds] + ] + ); + + $this->attributeSetRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->attributeSetInterfaceMock); + + $this->searchCriteriaBuilderMock->expects($this->any()) + ->method('addFilter') + ->willReturnSelf(); + $this->searchCriteriaBuilderMock->expects($this->any()) + ->method('create') + ->willReturn($this->searchCriteriaMock); + $this->searchCriteriaBuilderMock->expects($this->once()) + ->method('setPageSize') + ->willReturnSelf(); + $this->searchCriteriaBuilderMock->expects($this->never()) + ->method('addSortOrder') + ->willReturnSelf(); + + $this->attributeGroupRepositoryMock->expects($this->once()) + ->method('getList') + ->willReturn($this->attributeGroupSearchResultsMock); + $this->attributeGroupSearchResultsMock->expects($this->once()) + ->method('getItems') + ->willReturn(null); + + $this->attributeGroupInterfaceFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->attributeGroupInterfaceMock); + $this->attributeGroupInterfaceMock->expects($this->once()) + ->method('getExtensionAttributes') + ->willThrowException(new LocalizedException(__('Could not get extension attributes'))); + + $this->resultJsonFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->jsonMock); + $this->jsonMock->expects($this->once())->method('setJsonData') + ->willReturnSelf(); + + $this->controller->execute(); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/EditTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/EditTest.php index be6cd55729922..b2eb887f04b7a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/EditTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Attribute/EditTest.php @@ -1,6 +1,6 @@ objectManager = new ObjectManager($this); - $this->productLinkFactoryMock = $this->getMockBuilder(ProductLinkInterfaceFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->productRepositoryMock = $this->getMockBuilder(ProductRepository::class) - ->disableOriginalConstructor() - ->getMock(); $this->requestMock = $this->getMockBuilder(RequestInterface::class) ->setMethods(['getPost']) ->getMockForAbstractClass(); - $this->storeMock = $this->getMockBuilder(StoreInterface::class) - ->setMethods(['getWebsite']) - ->getMockForAbstractClass(); - $this->websiteMock = $this->getMockBuilder(WebsiteInterface::class) - ->getMockForAbstractClass(); $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) ->getMockForAbstractClass(); - $this->dateFilterMock = $this->getMockBuilder(DateFilter::class) - ->disableOriginalConstructor() - ->getMock(); $this->stockFilterMock = $this->getMockBuilder(StockDataFilter::class) ->disableOriginalConstructor() ->getMock(); $this->productMock = $this->getMockBuilder(Product::class) - ->setMethods([ - 'setData', - 'addData', - 'getId', - 'setWebsiteIds', - 'isLockedAttribute', - 'lockAttribute', - 'getAttributes', - 'unlockAttribute', - 'getOptionsReadOnly', - 'setOptions', - 'setCanSaveCustomOptions', - '__sleep', - '__wakeup', - 'getSku', - 'getProductLinks', - 'getWebsiteIds' - ]) + ->setMethods( + [ + 'getId', + 'isLockedAttribute', + 'lockAttribute', + 'getAttributes', + 'unlockAttribute', + 'getOptionsReadOnly', + 'getSku', + 'getProductLinks', + ] + ) ->disableOriginalConstructor() - ->getMock(); + ->getMockForAbstractClass(); $this->customOptionFactoryMock = $this->getMockBuilder(ProductCustomOptionInterfaceFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $this->customOptionMock = $this->getMockBuilder(ProductCustomOptionInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); $this->productLinksMock = $this->getMockBuilder(ProductLinks::class) ->disableOriginalConstructor() ->getMock(); - $this->productLinksMock->expects($this->any()) ->method('initializeLinks') ->willReturn($this->productMock); @@ -175,10 +112,7 @@ protected function setUp() 'storeManager' => $this->storeManagerMock, 'stockFilter' => $this->stockFilterMock, 'productLinks' => $this->productLinksMock, - 'dateFilter' => $this->dateFilterMock, 'customOptionFactory' => $this->customOptionFactoryMock, - 'productLinkFactory' => $this->productLinkFactoryMock, - 'productRepository' => $this->productRepositoryMock, ]); $this->linkResolverMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Link\Resolver::class) @@ -192,22 +126,23 @@ protected function setUp() /** * @covers \Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper::initialize - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @param bool $isSingleStore + * @param array $websiteIds + * @param array $expWebsiteIds + * + * @dataProvider initializeDataProvider */ - public function testInitialize() + public function testInitialize($isSingleStore, $websiteIds, $expWebsiteIds) { - $this->customOptionMock->expects($this->once()) - ->method('setProductSku'); - $this->customOptionMock->expects($this->once()) - ->method('setOptionId'); - $optionsData = [ - 'option1' => ['is_delete' => true, 'name' => 'name1', 'price' => 'price1'], - 'option2' => ['is_delete' => false, 'name' => 'name1', 'price' => 'price1'], + 'option1' => ['is_delete' => true, 'name' => 'name1', 'price' => 'price1', 'option_id' => ''], + 'option2' => ['is_delete' => false, 'name' => 'name1', 'price' => 'price1', 'option_id' => '13'], + 'option3' => ['is_delete' => false, 'name' => 'name1', 'price' => 'price1', 'option_id' => '14'] ]; $productData = [ 'stock_data' => ['stock_data'], 'options' => $optionsData, + 'website_ids' => $websiteIds ]; $attributeNonDate = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) ->disableOriginalConstructor() @@ -224,82 +159,95 @@ public function testInitialize() ->disableOriginalConstructor() ->getMock(); - $attributeNonDate->expects($this->any()) - ->method('getBackend') - ->willReturn($attributeNonDateBackEnd); - $attributeDate->expects($this->any()) - ->method('getBackend') - ->willReturn($attributeDateBackEnd); - $this->productMock->expects($this->any()) - ->method('getProductLinks') - ->willReturn([]); - $attributeNonDateBackEnd->expects($this->any()) - ->method('getType') - ->willReturn('non-datetime'); - $attributeDateBackEnd->expects($this->any()) - ->method('getType') - ->willReturn('datetime'); - - $attributesArray = [ - $attributeNonDate, - $attributeDate - ]; + $attributeNonDate->expects($this->any())->method('getBackend')->willReturn($attributeNonDateBackEnd); + $attributeDate->expects($this->any())->method('getBackend')->willReturn($attributeDateBackEnd); + $this->productMock->expects($this->any())->method('getProductLinks')->willReturn([]); + $attributeNonDateBackEnd->expects($this->any())->method('getType')->willReturn('non-datetime'); + $attributeDateBackEnd->expects($this->any())->method('getType')->willReturn('datetime'); $useDefaults = ['attributeCode1', 'attributeCode2']; - $this->requestMock->expects($this->at(0)) - ->method('getPost') - ->with('product') - ->willReturn($productData); - $this->requestMock->expects($this->at(1)) - ->method('getPost') - ->with('use_default') - ->willReturn($useDefaults); + $this->requestMock->expects($this->any())->method('getPost')->willReturnMap( + [ + ['product', [], $productData], + ['use_default', null, $useDefaults] + ] + ); $this->linkResolverMock->expects($this->once())->method('getLinks')->willReturn([]); - $this->stockFilterMock->expects($this->once()) - ->method('filter') - ->with(['stock_data']) + $this->stockFilterMock->expects($this->once())->method('filter')->with(['stock_data']) ->willReturn(['stock_data']); - $this->productMock->expects($this->once()) - ->method('isLockedAttribute') - ->with('media') - ->willReturn(true); - $this->productMock->expects($this->once()) - ->method('unlockAttribute') - ->with('media'); - $this->productMock->expects($this->any()) - ->method('getProductLinks') - ->willReturn([]); - $this->productMock->expects($this->once()) - ->method('lockAttribute') - ->with('media'); - $this->productMock->expects($this->once()) - ->method('getAttributes') - ->willReturn($attributesArray); - - $productData['category_ids'] = []; - $productData['website_ids'] = []; - unset($productData['options']); - - $this->productMock->expects($this->once()) - ->method('addData') - ->with($productData); - $this->productMock->expects($this->once()) - ->method('getSku') - ->willReturn('sku'); - $this->productMock->expects($this->any()) - ->method('getOptionsReadOnly') - ->willReturn(false); - + $this->productMock->expects($this->once())->method('isLockedAttribute')->with('media')->willReturn(true); + $this->productMock->expects($this->once())->method('unlockAttribute')->with('media'); + $this->productMock->expects($this->any())->method('getProductLinks')->willReturn([]); + $this->productMock->expects($this->once())->method('lockAttribute')->with('media'); + $this->productMock->expects($this->once())->method('getAttributes') + ->willReturn([$attributeNonDate, $attributeDate]); + $this->productMock->expects($this->any())->method('getSku')->willReturn('sku'); + $this->productMock->expects($this->any())->method('getOptionsReadOnly')->willReturn(false); + + $customOptionMock = $this->getMockBuilder(Option::class) + ->disableOriginalConstructor() + ->setMethods(null) + ->getMock(); + $firstExpectedCustomOption = clone $customOptionMock; + $firstExpectedCustomOption->setData($optionsData['option2']); + $secondExpectedCustomOption = clone $customOptionMock; + $secondExpectedCustomOption->setData($optionsData['option3']); $this->customOptionFactoryMock->expects($this->any()) ->method('create') - ->with(['data' => $optionsData['option2']]) - ->willReturn($this->customOptionMock); - $this->productMock->expects($this->once()) - ->method('setOptions') - ->with([$this->customOptionMock]); + ->willReturnMap([ + [ + ['data' => $optionsData['option2']], + $firstExpectedCustomOption + ], [ + ['data' => $optionsData['option3']], + $secondExpectedCustomOption + ] + ]); + $website = $this->getMockBuilder(WebsiteInterface::class)->getMockForAbstractClass(); + $website->expects($this->any())->method('getId')->willReturn(1); + $this->storeManagerMock->expects($this->once())->method('isSingleStoreMode')->willReturn($isSingleStore); + $this->storeManagerMock->expects($this->any())->method('getWebsite')->willReturn($website); $this->assertEquals($this->productMock, $this->helper->initialize($this->productMock)); + $this->assertEquals($expWebsiteIds, $this->productMock->getDataByKey('website_ids')); + + $productOptions = $this->productMock->getOptions(); + $this->assertTrue(2 == count($productOptions)); + list($option2, $option3) = $productOptions; + $this->assertTrue($option2->getOptionId() == $optionsData['option2']['option_id']); + $this->assertTrue('sku' == $option2->getData('product_sku')); + $this->assertTrue($option3->getOptionId() == $optionsData['option3']['option_id']); + $this->assertTrue('sku' == $option2->getData('product_sku')); + } + + /** + * @return array + */ + public function initializeDataProvider() + { + return [ + [ + 'single_store' => false, + 'website_ids' => ['1' => 1, '2' => 1], + 'expected_website_ids' => ['1' => 1, '2' => 1] + ], + [ + 'single_store' => false, + 'website_ids' => ['1' => 1, '2' => 0], + 'expected_website_ids' => ['1' => 1] + ], + [ + 'single_store' => false, + 'website_ids' => ['1' => 0, '2' => 0], + 'expected_website_ids' => [] + ], + [ + 'single_store' => true, + 'website_ids' => [], + 'expected_website_ids' => ['1' => 1] + ], + ]; } /** @@ -362,9 +310,9 @@ public function mergeProductOptionsDataProvider() [ 'option_id' => '5', 'key1' => 'val1', - 'key2' => 'val2', + 'title' => 'val2', 'default_key1' => 'val3', - 'default_key2' => 'val4', + 'default_title' => 'val4', 'values' => [ [ 'option_type_id' => '2', @@ -379,7 +327,7 @@ public function mergeProductOptionsDataProvider() [ 5 => [ 'key1' => '0', - 'key2' => '1', + 'title' => '1', 'values' => [2 => ['key1' => 1]] ] ], @@ -387,9 +335,10 @@ public function mergeProductOptionsDataProvider() [ 'option_id' => '5', 'key1' => 'val1', - 'key2' => 'val4', + 'title' => 'val4', 'default_key1' => 'val3', - 'default_key2' => 'val4', + 'default_title' => 'val4', + 'is_delete_store_title' => 1, 'values' => [ [ 'option_type_id' => '2', @@ -413,8 +362,9 @@ public function mergeProductOptionsDataProvider() [ 'option_type_id' => '2', 'key1' => 'val1', - 'key2' => 'val2', - 'default_key1' => 'val11' + 'title' => 'val2', + 'default_key1' => 'val11', + 'default_title' => 'val22' ] ] ] @@ -423,7 +373,7 @@ public function mergeProductOptionsDataProvider() 7 => [ 'key1' => '1', 'key2' => '1', - 'values' => [2 => ['key1' => 1, 'key2' => 1]] + 'values' => [2 => ['key1' => 0, 'title' => 1]] ] ], [ @@ -435,9 +385,11 @@ public function mergeProductOptionsDataProvider() 'values' => [ [ 'option_type_id' => '2', - 'key1' => 'val11', - 'key2' => 'val2', - 'default_key1' => 'val11' + 'key1' => 'val1', + 'title' => 'val22', + 'default_key1' => 'val11', + 'default_title' => 'val22', + 'is_delete_store_title' => 1 ] ] ] diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/StockDataFilterTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/StockDataFilterTest.php index a226ce91b24d1..384db2dcb72b6 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/StockDataFilterTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/StockDataFilterTest.php @@ -1,6 +1,6 @@ priceProcessor = $this->getMockBuilder(\Magento\Catalog\Model\Indexer\Product\Price\Processor::class) + $this->priceProcessorMock = $this->getMockBuilder(Processor::class) ->disableOriginalConstructor()->getMock(); + $this->productBuilderMock = $this->getMockBuilder(Builder::class) + ->setMethods(['build']) + ->disableOriginalConstructor() + ->getMock(); - $productBuilder = $this->getMockBuilder( - \Magento\Catalog\Controller\Adminhtml\Product\Builder::class - )->setMethods(['build'])->disableOriginalConstructor()->getMock(); - - $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)->disableOriginalConstructor() - ->setMethods(['getTypeId', 'getStoreId', '__sleep', '__wakeup'])->getMock(); - $product->expects($this->any())->method('getTypeId')->will($this->returnValue('simple')); - $product->expects($this->any())->method('getStoreId')->will($this->returnValue('1')); - $productBuilder->expects($this->any())->method('build')->will($this->returnValue($product)); + $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->setMethods(['getTypeId', 'getStoreId', '__sleep', '__wakeup']) + ->getMock(); + $productMock->expects($this->any()) + ->method('getTypeId') + ->willReturn('simple'); + $productMock->expects($this->any()) + ->method('getStoreId') + ->willReturn('1'); + $this->productBuilderMock->expects($this->any()) + ->method('build') + ->willReturn($productMock); - $this->resultRedirect = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) + $this->resultRedirectMock = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) ->disableOriginalConstructor() ->getMock(); $resultFactory = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) @@ -41,47 +83,71 @@ protected function setUp() $resultFactory->expects($this->atLeastOnce()) ->method('create') ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($this->resultRedirect); + ->willReturn($this->resultRedirectMock); - $abstractDbMock = $this->getMockBuilder(\Magento\Framework\Data\Collection\AbstractDb::class) + $this->abstractDbMock = $this->getMockBuilder(AbstractDb::class) ->disableOriginalConstructor() ->setMethods(['getAllIds', 'getResource']) ->getMock(); - $abstractDbMock->expects($this->any()) - ->method('getAllIds') - ->willReturn([]); - - $filterMock = $this->getMockBuilder(\Magento\Ui\Component\MassAction\Filter::class) + $this->filterMock = $this->getMockBuilder(\Magento\Ui\Component\MassAction\Filter::class) ->disableOriginalConstructor() ->setMethods(['getCollection']) ->getMock(); - $filterMock->expects($this->any()) - ->method('getCollection') - ->willReturn($abstractDbMock); - - $collectionFactoryMock = $this->getMockBuilder( - \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class - ) + $this->actionMock = $this->getMockBuilder(Action::class) + ->disableOriginalConstructor() + ->getMock(); + + $collectionFactoryMock = + $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); $collectionFactoryMock->expects($this->any()) ->method('create') - ->willReturn($abstractDbMock); + ->willReturn($this->abstractDbMock); + + $additionalParams = [ + 'resultFactory' => $resultFactory + ]; + /** @var \Magento\Backend\App\Action\Context $context */ + $context = $this->initContext($additionalParams, [[Action::class, $this->actionMock]]); - $additionalParams = ['resultFactory' => $resultFactory]; $this->action = new \Magento\Catalog\Controller\Adminhtml\Product\MassStatus( - $this->initContext($additionalParams), - $productBuilder, - $this->priceProcessor, - $filterMock, + $context, + $this->productBuilderMock, + $this->priceProcessorMock, + $this->filterMock, $collectionFactoryMock ); } public function testMassStatusAction() { - $this->priceProcessor->expects($this->once())->method('reindexList'); + $storeId = 1; + $status = \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED; + $filters = [ + 'store_id' => 2, + ]; + + $this->filterMock->expects($this->once()) + ->method('getCollection') + ->willReturn($this->abstractDbMock); + $this->abstractDbMock->expects($this->once()) + ->method('getAllIds') + ->willReturn([3]); + $this->request->expects($this->exactly(3)) + ->method('getParam') + ->willReturnMap([ + ['store', 0, $storeId], + ['status', null, $status], + ['filters', [], $filters] + ]); + $this->actionMock->expects($this->once()) + ->method('updateAttributes') + ->with([3], ['status' => $status], 2); + $this->priceProcessorMock->expects($this->once()) + ->method('reindexList'); + $this->action->execute(); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php index f8754ce00e50d..71f729ffec9d1 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php @@ -1,7 +1,7 @@ getMock(\Magento\Catalog\Model\Product\Action::class, [], [], '', false); - $objectManagerMock = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class); - $objectManagerMock->expects($this->any())->method('get')->will($this->returnValue($productActionMock)); + + $this->objectManagerMock = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class); + + if ($objectManagerMap) { + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap($objectManagerMap); + } + + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->willReturn($productActionMock); $block = $this->getMockBuilder(\Magento\Framework\View\Element\AbstractBlock::class) ->disableOriginalConstructor()->getMockForAbstractClass(); @@ -93,7 +111,7 @@ protected function initContext(array $additionalParams = []) $this->context->expects($this->any())->method('getEventManager')->will($this->returnValue($eventManager)); $this->context->expects($this->any())->method('getRequest')->will($this->returnValue($requestInterfaceMock)); $this->context->expects($this->any())->method('getResponse')->will($this->returnValue($responseInterfaceMock)); - $this->context->expects($this->any())->method('getObjectManager')->will($this->returnValue($objectManagerMock)); + $this->context->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock); $this->context->expects($this->any())->method('getMessageManager') ->will($this->returnValue($managerInterfaceMock)); diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Category/MoveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Category/MoveTest.php new file mode 100644 index 0000000000000..035218ee57918 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Category/MoveTest.php @@ -0,0 +1,320 @@ +resultJsonFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\JsonFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->layoutFactoryMock = $this->getMockBuilder(\Magento\Framework\View\LayoutFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->context = $this->getMock(\Magento\Backend\App\Action\Context::class, [], [], '', false); + $this->loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class); + $this->fillContext(); + + $this->moveController = new Move( + $this->context, + $this->resultJsonFactoryMock, + $this->layoutFactoryMock, + $this->loggerMock + ); + $this->initObjectManager(); + } + + private function fillContext() + { + $this->request = $this + ->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->setMethods(['getPost']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->context->expects($this->once())->method('getRequest')->will($this->returnValue($this->request)); + $this->messageManager = $this->getMock(ManagerInterface::class); + $this->context->expects($this->once())->method('getMessageManager')->willReturn($this->messageManager); + } + + private function initObjectManager() + { + $this->objectManager = $this->getMock(ObjectManagerInterface::class); + $moveController = new \ReflectionClass($this->moveController); + $objectManagerProp = $moveController->getProperty('_objectManager'); + $objectManagerProp->setAccessible(true); + $objectManagerProp->setValue($this->moveController, $this->objectManager); + } + + public function testExecuteWithGenericException() + { + $messagesCollection = $this->getMockBuilder(\Magento\Framework\Message\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $messageBlock = $this->getMockBuilder(\Magento\Framework\View\Element\Messages::class) + ->disableOriginalConstructor() + ->getMock(); + $layoutMock = $this->getMock(\Magento\Framework\View\LayoutInterface::class); + $this->layoutFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($layoutMock); + $layoutMock->expects($this->once()) + ->method('getMessagesBlock') + ->willReturn($messageBlock); + $wysiwigConfig = $this->getMockBuilder(\Magento\Cms\Model\Wysiwyg\Config::class) + ->disableOriginalConstructor() + ->getMock(); + $registry = $this->getMockBuilder(Registry::class) + ->disableOriginalConstructor() + ->getMock(); + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); + $this->request->expects($this->exactly(2)) + ->method('getPost') + ->withConsecutive(['pid', false], ['aid', false]) + ->willReturnMap([['pid', false, 2], ['aid', false, 1]]); + $this->objectManager->expects($this->once()) + ->method('create') + ->with(\Magento\Catalog\Model\Category::class) + ->willReturn($categoryMock); + $this->objectManager->expects($this->any()) + ->method('get') + ->withConsecutive([Registry::class], [Registry::class], [\Magento\Cms\Model\Wysiwyg\Config::class]) + ->willReturnMap([[Registry::class, $registry], [\Magento\Cms\Model\Wysiwyg\Config::class, $wysiwigConfig]]); + $categoryMock->expects($this->once()) + ->method('move') + ->willThrowException(new \Exception( + __('Some exception') + )); + $this->messageManager->expects($this->once()) + ->method('addError') + ->with(__('There was a category move error.')); + $this->messageManager->expects($this->once()) + ->method('getMessages') + ->with(true) + ->willReturn($messagesCollection); + $messageBlock->expects($this->once()) + ->method('setMessages') + ->with($messagesCollection); + $resultJsonMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Json::class) + ->disableOriginalConstructor() + ->getMock(); + $messageBlock->expects($this->once()) + ->method('getGroupedHtml') + ->willReturn(''); + $resultJsonMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'messages' => '', + 'error' => true + ] + ) + ->willReturn(true); + $this->resultJsonFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($resultJsonMock); + $this->assertTrue($this->moveController->execute()); + } + + public function testExecuteWithLocaliedException() + { + $exceptionMessage = 'Sorry, but we can\'t find the new category you selected.'; + $messagesCollection = $this->getMockBuilder(\Magento\Framework\Message\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $messageBlock = $this->getMockBuilder(\Magento\Framework\View\Element\Messages::class) + ->disableOriginalConstructor() + ->getMock(); + $layoutMock = $this->getMock(\Magento\Framework\View\LayoutInterface::class); + $this->layoutFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($layoutMock); + $layoutMock->expects($this->once()) + ->method('getMessagesBlock') + ->willReturn($messageBlock); + $wysiwigConfig = $this->getMockBuilder(\Magento\Cms\Model\Wysiwyg\Config::class) + ->disableOriginalConstructor() + ->getMock(); + $registry = $this->getMockBuilder(Registry::class) + ->disableOriginalConstructor() + ->getMock(); + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); + $this->request->expects($this->exactly(2)) + ->method('getPost') + ->withConsecutive(['pid', false], ['aid', false]) + ->willReturnMap([['pid', false, 2], ['aid', false, 1]]); + $this->objectManager->expects($this->once()) + ->method('create') + ->with(\Magento\Catalog\Model\Category::class) + ->willReturn($categoryMock); + $this->objectManager->expects($this->any()) + ->method('get') + ->withConsecutive([Registry::class], [Registry::class], [\Magento\Cms\Model\Wysiwyg\Config::class]) + ->willReturnMap([[Registry::class, $registry], [\Magento\Cms\Model\Wysiwyg\Config::class, $wysiwigConfig]]); + $this->messageManager->expects($this->once()) + ->method('addError') + ->with($exceptionMessage); + $this->messageManager->expects($this->once()) + ->method('getMessages') + ->with(true) + ->willReturn($messagesCollection); + $messageBlock->expects($this->once()) + ->method('setMessages') + ->with($messagesCollection); + $resultJsonMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Json::class) + ->disableOriginalConstructor() + ->getMock(); + $messageBlock->expects($this->once()) + ->method('getGroupedHtml') + ->willReturn(''); + $resultJsonMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'messages' => '', + 'error' => true + ] + ) + ->willReturn(true); + $categoryMock->expects($this->once()) + ->method('move') + ->willThrowException(new \Magento\Framework\Exception\LocalizedException( + __($exceptionMessage) + )); + $this->resultJsonFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($resultJsonMock); + $this->assertTrue($this->moveController->execute()); + } + + public function testSuccessfullCategorySave() + { + $messagesCollection = $this->getMockBuilder(\Magento\Framework\Message\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $messageBlock = $this->getMockBuilder(\Magento\Framework\View\Element\Messages::class) + ->disableOriginalConstructor() + ->getMock(); + $layoutMock = $this->getMock(\Magento\Framework\View\LayoutInterface::class); + $this->layoutFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($layoutMock); + $layoutMock->expects($this->once()) + ->method('getMessagesBlock') + ->willReturn($messageBlock); + $wysiwigConfig = $this->getMockBuilder(\Magento\Cms\Model\Wysiwyg\Config::class) + ->disableOriginalConstructor() + ->getMock(); + $registry = $this->getMockBuilder(Registry::class) + ->disableOriginalConstructor() + ->getMock(); + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); + $this->request->expects($this->exactly(2)) + ->method('getPost') + ->withConsecutive(['pid', false], ['aid', false]) + ->willReturnMap([['pid', false, 2], ['aid', false, 1]]); + $this->objectManager->expects($this->once()) + ->method('create') + ->with(\Magento\Catalog\Model\Category::class) + ->willReturn($categoryMock); + $this->objectManager->expects($this->any()) + ->method('get') + ->withConsecutive([Registry::class], [Registry::class], [\Magento\Cms\Model\Wysiwyg\Config::class]) + ->willReturnMap([[Registry::class, $registry], [\Magento\Cms\Model\Wysiwyg\Config::class, $wysiwigConfig]]); + $this->messageManager->expects($this->once()) + ->method('getMessages') + ->with(true) + ->willReturn($messagesCollection); + $messageBlock->expects($this->once()) + ->method('setMessages') + ->with($messagesCollection); + $resultJsonMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Json::class) + ->disableOriginalConstructor() + ->getMock(); + $messageBlock->expects($this->once()) + ->method('getGroupedHtml') + ->willReturn(''); + $resultJsonMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'messages' => '', + 'error' => false + ] + ) + ->willReturn(true); + $this->messageManager->expects($this->once()) + ->method('addSuccess') + ->with(__('You moved the category.')); + $categoryMock->expects($this->once()) + ->method('move') + ->with(2, 1); + $this->resultJsonFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($resultJsonMock); + $this->assertTrue($this->moveController->execute()); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php index d8c18300a31f2..de475da82d206 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Category/ViewTest.php @@ -1,6 +1,6 @@ image->expects($this->any()) ->method('isBaseFilePlaceholder') ->willReturn($isBaseFilePlaceholder); - $this->image->expects($this->any()) - ->method('getNewFile') - ->willReturn($newFile); $this->prepareAttributes([], $imageId); @@ -502,7 +497,6 @@ public function getResizedImageInfoDataProvider() 'image_id' => 'test_image_id', 'image_file' => '/path/to/test_image_id.png', 'base_file' => '/path/to/base_image.png', - 'new_file' => '/path/to/base_image.png', 'destination' => 'small_image', 'set_image_file' => true, 'is_cached' => false, @@ -516,7 +510,6 @@ public function getResizedImageInfoDataProvider() 'image_id' => 'test_image_id', 'image_file' => '/path/to/test_image_id.png', 'base_file' => null, - 'new_file' => true, 'destination' => 'small_image', 'set_image_file' => false, 'is_cached' => false, @@ -530,7 +523,6 @@ public function getResizedImageInfoDataProvider() 'image_id' => 'test_image_id', 'image_file' => '/path/to/test_image_id.png', 'base_file' => null, - 'new_file' => false, 'destination' => 'small_image', 'set_image_file' => true, 'is_cached' => false, @@ -544,7 +536,6 @@ public function getResizedImageInfoDataProvider() 'image_id' => 'test_image_id', 'image_file' => '/path/to/test_image_id.png', 'base_file' => null, - 'new_file' => true, 'destination' => 'small_image', 'set_image_file' => true, 'is_cached' => false, @@ -558,7 +549,6 @@ public function getResizedImageInfoDataProvider() 'image_id' => 'test_image_id', 'image_file' => '/path/to/test_image_id.png', 'base_file' => null, - 'new_file' => '/path/to/test_image_id.png', 'destination' => 'small_image', 'set_image_file' => true, 'is_cached' => false, diff --git a/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php index 29786ecdce969..997db3a409b7f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/CompareTest.php @@ -1,6 +1,6 @@ strtr(base64_encode($compareListUrl), '+/=', '-_,'), - 'product' => $productId + Action::PARAM_NAME_URL_ENCODED => '', + 'product' => $productId, + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove this item from your Compare Products list?'), ]; //Verification - $this->urlBuilder->expects($this->at(0)) - ->method('getUrl') - ->with($compareListUrl) - ->will($this->returnValue($compareListUrl)); - $this->urlBuilder->expects($this->at(1)) + $this->urlBuilder->expects($this->once()) ->method('getUrl') ->with($removeUrl) ->will($this->returnValue($removeUrl)); @@ -159,18 +156,14 @@ public function testGetClearListUrl() public function testGetPostDataClearList() { //Data - $refererUrl = 'home/'; $clearUrl = 'catalog/product_compare/clear'; $postParams = [ - Action::PARAM_NAME_URL_ENCODED => strtr(base64_encode($refererUrl), '+/=', '-_,') + Action::PARAM_NAME_URL_ENCODED => '', + 'confirmation' => true, + 'confirmationMessage' => __('Are you sure you want to remove all items from your Compare Products list?'), ]; //Verification - $this->request->expects($this->once()) - ->method('getServer') - ->with('HTTP_REFERER') - ->will($this->returnValue($refererUrl)); - $this->urlBuilder->expects($this->once()) ->method('getUrl') ->with($clearUrl) diff --git a/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationPoolTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationPoolTest.php index f7ef5095529ec..a852d5ab3e864 100644 --- a/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationPoolTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/ConfigurationPoolTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\App\Helper\Context::class, [], [], '', false); + $optionFactoryMock = $this->getMock(\Magento\Catalog\Model\Product\OptionFactory::class, [], [], '', false); + $filterManagerMock = $this->getMock(\Magento\Framework\Filter\FilterManager::class, [], [], '', false); + $stringUtilsMock = $this->getMock(\Magento\Framework\Stdlib\StringUtils::class, [], [], '', false); + $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class, [], [], '', false); + + $this->helper = new \Magento\Catalog\Helper\Product\Configuration( + $contextMock, + $optionFactoryMock, + $filterManagerMock, + $stringUtilsMock, + $this->serializer + ); + } + + /** + * Retrieves product additional options + */ + public function testGetAdditionalOptionOnly() + { + $additionalOptionResult = ['additional_option' => 1]; + + $itemMock = $this->getMock( + \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface::class, + [], + [], + '', + false + ); + $optionMock = $this->getMock( + \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class, + [], + [], + '', + false + ); + $additionalOptionMock = $this->getMock( + \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class, + [], + [], + '', + false + ); + $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false); + + $this->serializer->expects($this->once())->method('unserialize')->willReturn($additionalOptionResult); + $optionMock->expects($this->once())->method('getValue')->willReturn(null); + $additionalOptionMock->expects($this->once())->method('getValue'); + + $itemMock->expects($this->once())->method('getProduct')->willReturn($productMock); + $itemMock->expects($this->any())->method('getOptionByCode')->will($this->returnValueMap( + [ + ['option_ids', $optionMock], + ['additional_options', $additionalOptionMock] + ] + )); + + $this->assertEquals($additionalOptionResult, $this->helper->getCustomOptions($itemMock)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Helper/Product/Edit/Action/AttributeTest.php b/app/code/Magento/Catalog/Test/Unit/Helper/Product/Edit/Action/AttributeTest.php index a6b11d7993950..04faa6bdf03d8 100644 --- a/app/code/Magento/Catalog/Test/Unit/Helper/Product/Edit/Action/AttributeTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Helper/Product/Edit/Action/AttributeTest.php @@ -1,6 +1,6 @@ ['test_attribute'], 'group_two' => ['attribute_one', 'attribute_two']]; diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_merged.xml b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_merged.xml index 131fe397f2e6b..813e9d64af710 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_merged.xml +++ b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_merged.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_one.xml b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_one.xml index 3e11d226e6af4..3fe4cc449c51d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_one.xml +++ b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_one.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_two.xml b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_two.xml index 772a85eafe95e..718895e7117fb 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_two.xml +++ b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Config/_files/attributes_config_two.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/ConfigTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/ConfigTest.php index 358a5ed67e63d..64a26b7cd8664 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/ConfigTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/ConfigTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->attribute = $this->getMockForAbstractClass( + \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class, + [], + 'TestAttribute', + false, + false, + true, + ['getName'] + ); + + $this->attribute->expects($this->once()) + ->method('getName') + ->will($this->returnValue('test_attribute')); + + $this->logger = $this->getMockForAbstractClass( + \Psr\Log\LoggerInterface::class, + [], + 'TestLogger', + false, + false, + true, + ['critical'] + ); + + $this->imageUploader = $this->getMock( + \Magento\Catalog\Model\ImageUploader::class, + ['moveFileFromTmp'], + [], + '', + false + ); + } + + /** + * @return array + */ + public function deletedValueDataProvider() + { + return [ + [false], + [['delete' => true]] + ]; + } + + /** + * @dataProvider deletedValueDataProvider + * + * @param array $value + */ + public function testBeforeSaveValueDeletion($value) + { + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); + $model->setAttribute($this->attribute); + + $object = new \Magento\Framework\DataObject([ + 'test_attribute' => $value + ]); + + $model->beforeSave($object); + + $this->assertEquals('', $object->getTestAttribute()); + } + + /** + * @return array + */ + public function invalidValueDataProvider() + { + $closure = function () { + return false; + }; + + return [ + [1234], + [true], + [new \stdClass()], + [$closure], + [['a' => 1, 'b' => 2]] + ]; + } + + /** + * @dataProvider invalidValueDataProvider + * + * @param array $value + */ + public function testBeforeSaveValueInvalid($value) + { + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); + $model->setAttribute($this->attribute); + + $object = new \Magento\Framework\DataObject([ + 'test_attribute' => $value + ]); + + $model->beforeSave($object); + + $this->assertEquals('', $object->getTestAttribute()); + } + + public function testBeforeSaveAttributeFileName() + { + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); + $model->setAttribute($this->attribute); + + $object = new \Magento\Framework\DataObject([ + 'test_attribute' => [ + ['name' => 'test123.jpg'] + ] + ]); + + $model->beforeSave($object); + + $this->assertEquals('test123.jpg', $object->getTestAttribute()); + } + + public function testBeforeSaveTemporaryAttribute() + { + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); + $model->setAttribute($this->attribute); + + $object = new \Magento\Framework\DataObject([ + 'test_attribute' => [ + ['name' => 'test123.jpg', 'tmp_name' => 'abc123', 'url' => 'http://www.example.com/test123.jpg'] + ] + ]); + + $model->beforeSave($object); + + $this->assertEquals([ + ['name' => 'test123.jpg', 'tmp_name' => 'abc123', 'url' => 'http://www.example.com/test123.jpg'] + ], $object->getData('_additional_data_test_attribute')); + } + + public function testBeforeSaveAttributeStringValue() + { + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); + $model->setAttribute($this->attribute); + + $object = new \Magento\Framework\DataObject([ + 'test_attribute' => 'test123.jpg' + ]); + + $model->beforeSave($object); + + $this->assertEquals('test123.jpg', $object->getTestAttribute()); + $this->assertNull($object->getData('_additional_data_test_attribute')); + } + + /** + * @return \Magento\Catalog\Model\Category\Attribute\Backend\Image + */ + private function setUpModelForAfterSave() + { + $objectManagerMock = $this->getMock( + \Magento\Framework\App\ObjectManager::class, + ['get'], + [], + '', + false + ); + + $imageUploaderMock = $this->imageUploader; + + $objectManagerMock->expects($this->any()) + ->method('get') + ->will($this->returnCallback(function ($class, $params = []) use ($imageUploaderMock) { + if ($class == \Magento\Catalog\CategoryImageUpload::class) { + return $imageUploaderMock; + } + + return $this->objectManager->get($class, $params); + })); + + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class, [ + 'objectManager' => $objectManagerMock, + 'logger' => $this->logger + ]); + $this->objectManager->setBackwardCompatibleProperty($model, 'imageUploader', $this->imageUploader); + + return $model->setAttribute($this->attribute); + } + + public function attributeValueDataProvider() + { + return [ + [[['name' => 'test1234.jpg']]], + ['test1234.jpg'], + [''], + [false] + ]; + } + + /** + * @dataProvider attributeValueDataProvider + * + * @param array $value + */ + public function testAfterSaveWithAdditionalData($value) + { + $model = $this->setUpModelForAfterSave(); + + $this->imageUploader->expects($this->once()) + ->method('moveFileFromTmp') + ->with($this->equalTo('test1234.jpg')); + + $object = new \Magento\Framework\DataObject( + [ + 'test_attribute' => $value, + '_additional_data_test_attribute' => [['name' => 'test1234.jpg']] + ] + ); + + $model->afterSave($object); + } + + /** + * @dataProvider attributeValueDataProvider + * + * @param array $value + */ + public function testAfterSaveWithoutAdditionalData($value) + { + $model = $this->setUpModelForAfterSave(); + + $this->imageUploader->expects($this->never()) + ->method('moveFileFromTmp'); + + $object = new \Magento\Framework\DataObject( + [ + 'test_attribute' => $value + ] + ); + + $model->afterSave($object); + } + + public function testAfterSaveWithExceptions() + { + $model = $this->setUpModelForAfterSave(); + + $exception = new \Exception(); + + $this->imageUploader->expects($this->any()) + ->method('moveFileFromTmp') + ->will($this->throwException($exception)); + + $this->logger->expects($this->once()) + ->method('critical') + ->with($this->equalTo($exception)); + + $object = new \Magento\Framework\DataObject( + [ + '_additional_data_test_attribute' => [['name' => 'test1234.jpg']] + ] + ); + + $model->afterSave($object); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/SortbyTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/SortbyTest.php index b720856d8554d..62c0fc6d9f535 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/SortbyTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/SortbyTest.php @@ -1,6 +1,6 @@ eavValidationRules = $this->getMockBuilder(EavValidationRules::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->collection = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->collection->expects($this->any()) + ->method('addAttributeToSelect') + ->with('*') + ->willReturnSelf(); + + $this->categoryCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->categoryCollectionFactory->expects($this->any()) + ->method('create') + ->willReturn($this->collection); + + $this->storeManager = $this->getMockBuilder(StoreManagerInterface::class) + ->getMockForAbstractClass(); + + $this->registry = $this->getMockBuilder(Registry::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->eavEntityMock = $this->getMockBuilder(Type::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->eavConfig = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->request = $this->getMockBuilder(RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->categoryFactory = $this->getMockBuilder(CategoryFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfo = $this->getMockBuilder(FileInfo::class) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @return DataProvider + */ + private function getModel() + { + $this->eavEntityMock->expects($this->any()) + ->method('getAttributeCollection') + ->willReturn([]); + + $this->eavConfig->expects($this->any()) + ->method('getEntityType') + ->with('catalog_category') + ->willReturn($this->eavEntityMock); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $model = $objectManager->getObject( + DataProvider::class, + [ + 'eavValidationRules' => $this->eavValidationRules, + 'categoryCollectionFactory' => $this->categoryCollectionFactory, + 'storeManager' => $this->storeManager, + 'registry' => $this->registry, + 'eavConfig' => $this->eavConfig, + 'request' => $this->request, + 'categoryFactory' => $this->categoryFactory, + ] + ); + + $objectManager->setBackwardCompatibleProperty( + $model, + 'fileInfo', + $this->fileInfo + ); + + return $model; + } + + public function testGetDataNoCategory() + { + $this->registry->expects($this->once()) + ->method('registry') + ->with('category') + ->willReturn(null); + + $model = $this->getModel(); + $this->assertNull($model->getData()); + } + + public function testGetDataNoFileExists() + { + $fileName = 'filename.ext1'; + $categoryId = 1; + + $categoryData = [ + 'image' => $fileName, + ]; + + $imageBackendMock = $this->getMockBuilder(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class) + ->disableOriginalConstructor() + ->getMock(); + + $attributeMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeMock->expects($this->once()) + ->method('getBackend') + ->willReturn($imageBackendMock); + + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); + $categoryMock->expects($this->exactly(2)) + ->method('getData') + ->willReturnMap([ + ['', null, $categoryData], + ['image', null, $categoryData['image']], + ]); + $categoryMock->expects($this->any()) + ->method('getExistsStoreValueFlag') + ->with('url_key') + ->willReturn(false); + $categoryMock->expects($this->any()) + ->method('getStoreId') + ->willReturn(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $categoryMock->expects($this->once()) + ->method('getId') + ->willReturn($categoryId); + $categoryMock->expects($this->once()) + ->method('getAttributes') + ->willReturn(['image' => $attributeMock]); + + $this->registry->expects($this->once()) + ->method('registry') + ->with('category') + ->willReturn($categoryMock); + + $this->fileInfo->expects($this->once()) + ->method('isExist') + ->with($fileName) + ->willReturn(false); + + $model = $this->getModel(); + $result = $model->getData(); + + $this->assertTrue(is_array($result)); + $this->assertArrayHasKey($categoryId, $result); + $this->assertArrayNotHasKey('image', $result[$categoryId]); + } + + public function testGetData() + { + $fileName = 'filename.png'; + $mime = 'image/png'; + $size = 1; + + $categoryId = 1; + $categoryUrl = 'category_url'; + + $categoryData = [ + 'image' => $fileName, + ]; + + $expects = [ + [ + 'name' => $fileName, + 'url' => $categoryUrl, + 'size' => $size, + 'type' => $mime, + ], + ]; + + $imageBackendMock = $this->getMockBuilder(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class) + ->disableOriginalConstructor() + ->getMock(); + + $attributeMock = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeMock->expects($this->once()) + ->method('getBackend') + ->willReturn($imageBackendMock); + + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); + $categoryMock->expects($this->exactly(2)) + ->method('getData') + ->willReturnMap([ + ['', null, $categoryData], + ['image', null, $categoryData['image']], + ]); + $categoryMock->expects($this->any()) + ->method('getExistsStoreValueFlag') + ->with('url_key') + ->willReturn(false); + $categoryMock->expects($this->any()) + ->method('getStoreId') + ->willReturn(\Magento\Store\Model\Store::DEFAULT_STORE_ID); + $categoryMock->expects($this->once()) + ->method('getId') + ->willReturn($categoryId); + $categoryMock->expects($this->once()) + ->method('getAttributes') + ->willReturn(['image' => $attributeMock]); + $categoryMock->expects($this->once()) + ->method('getImageUrl') + ->willReturn($categoryUrl); + + $this->registry->expects($this->once()) + ->method('registry') + ->with('category') + ->willReturn($categoryMock); + + $this->fileInfo->expects($this->once()) + ->method('isExist') + ->with($fileName) + ->willReturn(true); + $this->fileInfo->expects($this->once()) + ->method('getStat') + ->with($fileName) + ->willReturn(['size' => $size]); + $this->fileInfo->expects($this->once()) + ->method('getMimeType') + ->with($fileName) + ->willReturn($mime); + + $model = $this->getModel(); + $result = $model->getData(); + + $this->assertTrue(is_array($result)); + $this->assertArrayHasKey($categoryId, $result); + $this->assertArrayHasKey('image', $result[$categoryId]); + + $this->assertEquals($expects, $result[$categoryId]['image']); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/FileInfoTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/FileInfoTest.php new file mode 100644 index 0000000000000..973fa8555264a --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/FileInfoTest.php @@ -0,0 +1,114 @@ +mediaDirectory = $this->getMockBuilder(WriteInterface::class) + ->getMockForAbstractClass(); + + $this->filesystem = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + $this->filesystem->expects($this->any()) + ->method('getDirectoryWrite') + ->with(DirectoryList::MEDIA) + ->willReturn($this->mediaDirectory); + + $this->mime = $this->getMockBuilder(Mime::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new FileInfo( + $this->filesystem, + $this->mime + ); + } + + public function testGetMimeType() + { + $mediaPath = '/catalog/category'; + + $fileName = '/filename.ext1'; + $absoluteFilePath = '/absolute_path/catalog/category/filename.ext1'; + + $expected = 'ext1'; + + $this->mediaDirectory->expects($this->once()) + ->method('getAbsolutePath') + ->with($mediaPath. '/' . ltrim($fileName, '/')) + ->willReturn($absoluteFilePath); + + $this->mime->expects($this->once()) + ->method('getMimeType') + ->with($absoluteFilePath) + ->willReturn($expected); + + $this->assertEquals($expected, $this->model->getMimeType($fileName)); + } + + public function testGetStat() + { + $mediaPath = '/catalog/category'; + + $fileName = '/filename.ext1'; + + $expected = ['size' => 1]; + + $this->mediaDirectory->expects($this->once()) + ->method('stat') + ->with($mediaPath . $fileName) + ->willReturn($expected); + + $result = $this->model->getStat($fileName); + + $this->assertTrue(is_array($result)); + $this->assertArrayHasKey('size', $result); + $this->assertEquals(1, $result['size']); + } + + public function testIsExist() + { + $mediaPath = '/catalog/category'; + + $fileName = '/filename.ext1'; + + $this->mediaDirectory->expects($this->once()) + ->method('isExist') + ->with($mediaPath . $fileName) + ->willReturn(true); + + $this->assertTrue($this->model->isExist($fileName)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Link/ReadHandlerTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Link/ReadHandlerTest.php index 8be5ca3dba1ef..8d1068fb5172e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/Link/ReadHandlerTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Link/ReadHandlerTest.php @@ -1,6 +1,6 @@ context = $this->getMock( - \Magento\Framework\Model\Context::class, - ['getEventDispatcher', 'getCacheManager'], + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->registry = $this->getMock(\Magento\Framework\Registry::class); + $this->storeManager = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class); + $this->categoryTreeResource = $this->getMock( + \Magento\Catalog\Model\ResourceModel\Category\Tree::class, + [], [], '', false ); - - $this->eventManager = $this->getMock(\Magento\Framework\Event\ManagerInterface::class); - $this->context->expects($this->any())->method('getEventDispatcher') - ->will($this->returnValue($this->eventManager)); - $this->cacheManager = $this->getMock(\Magento\Framework\App\CacheInterface::class); - $this->context->expects($this->any())->method('getCacheManager') - ->will($this->returnValue($this->cacheManager)); - - $this->registry = $this->getMock(\Magento\Framework\Registry::class); - $this->storeManager = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class); - $this->categoryTreeResource = $this->getMock( - \Magento\Catalog\Model\ResourceModel\Category\Tree::class, - [], - [], - '', - false - ); - $this->categoryTreeFactory = $this->getMock( + $this->categoryTreeFactory = $this->getMock( \Magento\Catalog\Model\ResourceModel\Category\TreeFactory::class, ['create'], [], '', false); $this->categoryRepository = $this->getMock(\Magento\Catalog\Api\CategoryRepositoryInterface::class); - $this->storeCollectionFactory = $this->getMock( + $this->storeCollectionFactory = $this->getMock( \Magento\Store\Model\ResourceModel\Store\CollectionFactory::class, ['create'], [], @@ -130,7 +149,7 @@ protected function setUp() false ); $this->url = $this->getMock(\Magento\Framework\UrlInterface::class); - $this->productCollectionFactory = $this->getMock( + $this->productCollectionFactory = $this->getMock( \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class, ['create'], [], @@ -138,7 +157,7 @@ protected function setUp() false ); $this->catalogConfig = $this->getMock(\Magento\Catalog\Model\Config::class, [], [], '', false); - $this->filterManager = $this->getMock( + $this->filterManager = $this->getMock( \Magento\Framework\Filter\FilterManager::class, ['translitUrl'], [], @@ -148,7 +167,7 @@ protected function setUp() $this->flatState = $this->getMock(\Magento\Catalog\Model\Indexer\Category\Flat\State::class, [], [], '', false); $this->flatIndexer = $this->getMock(\Magento\Framework\Indexer\IndexerInterface::class); $this->productIndexer = $this->getMock(\Magento\Framework\Indexer\IndexerInterface::class); - $this->categoryUrlPathGenerator = $this->getMock( + $this->categoryUrlPathGenerator = $this->getMock( \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator::class, [], [], @@ -156,19 +175,19 @@ protected function setUp() false ); $this->urlFinder = $this->getMock(\Magento\UrlRewrite\Model\UrlFinderInterface::class); - $this->resource = $this->getMock( + $this->resource = $this->getMock( \Magento\Catalog\Model\ResourceModel\Category::class, [], [], '', false ); - $this->indexerRegistry = $this->getMock( - \Magento\Framework\Indexer\IndexerRegistry::class, - ['get'], - [], - '', - false + $this->indexerRegistry = $this->getMock( + \Magento\Framework\Indexer\IndexerRegistry::class, + ['get'], + [], + '', + false ); $this->metadataServiceMock = $this->getMock(\Magento\Catalog\Api\CategoryAttributeRepositoryInterface::class); @@ -198,7 +217,7 @@ public function testFormatUrlKey() public function testMoveWhenCannotFindParentCategory() { $this->markTestIncomplete('MAGETWO-31165'); - $parentCategory = $this->getMock( + $parentCategory = $this->getMock( \Magento\Catalog\Model\Category::class, ['getId', 'setStoreId', 'load'], [], @@ -223,7 +242,7 @@ public function testMoveWhenCannotFindParentCategory() */ public function testMoveWhenCannotFindNewCategory() { - $parentCategory = $this->getMock( + $parentCategory = $this->getMock( \Magento\Catalog\Model\Category::class, ['getId', 'setStoreId', 'load'], [], @@ -250,7 +269,7 @@ public function testMoveWhenCannotFindNewCategory() public function testMoveWhenParentCategoryIsSameAsChildCategory() { $this->markTestIncomplete('MAGETWO-31165'); - $parentCategory = $this->getMock( + $parentCategory = $this->getMock( \Magento\Catalog\Model\Category::class, ['getId', 'setStoreId', 'load'], [], @@ -277,7 +296,7 @@ public function testMovePrimaryWorkflow() ->method('get') ->with('catalog_category_product') ->will($this->returnValue($indexer)); - $parentCategory = $this->getMock( + $parentCategory = $this->getMock( \Magento\Catalog\Model\Category::class, ['getId', 'setStoreId', 'load'], [], @@ -313,10 +332,9 @@ public function testGetUseFlatResourceTrue() protected function getCategoryModel() { - return (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject( + return $this->objectManager->getObject( \Magento\Catalog\Model\Category::class, [ - 'context' => $this->context, 'registry' => $this->registry, 'storeManager' => $this->storeManager, 'categoryTreeResource' => $this->categoryTreeResource, @@ -487,4 +505,76 @@ public function testGetCustomAttributes() $this->category->getCustomAttribute($descriptionAttributeCode)->getValue() ); } + + /** + * @return array + */ + public function getImageWithAttributeCodeDataProvider() + { + return [ + ['testimage', 'http://www.example.com/catalog/category/testimage'], + [false, false] + ]; + } + + /** + * @param string|bool $value + * @param string|bool $url + * + * @dataProvider getImageWithAttributeCodeDataProvider + */ + public function testGetImageWithAttributeCode($value, $url) + { + $storeManager = $this->getMock(\Magento\Store\Model\StoreManager::class, ['getStore'], [], '', false); + $store = $this->getMock(\Magento\Store\Model\Store::class, ['getBaseUrl'], [], '', false); + + $storeManager->expects($this->any()) + ->method('getStore') + ->will($this->returnValue($store)); + + $store->expects($this->any()) + ->method('getBaseUrl') + ->with(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) + ->will($this->returnValue('http://www.example.com/')); + + /** @var \Magento\Catalog\Model\Category $model */ + $model = $this->objectManager->getObject( + \Magento\Catalog\Model\Category::class, + [ + 'storeManager' => $storeManager + ] + ); + + $model->setData('attribute1', $value); + + $result = $model->getImageUrl('attribute1'); + + $this->assertEquals($url, $result); + } + + public function testGetImageWithoutAttributeCode() + { + $storeManager = $this->getMock(\Magento\Store\Model\StoreManager::class, ['getStore'], [], '', false); + $store = $this->getMock(\Magento\Store\Model\Store::class, ['getBaseUrl'], [], '', false); + + $storeManager->expects($this->any()) + ->method('getStore') + ->will($this->returnValue($store)); + + $store->expects($this->any()) + ->method('getBaseUrl') + ->with(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) + ->will($this->returnValue('http://www.example.com/')); + + /** @var \Magento\Catalog\Model\Category $model */ + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category::class, [ + 'storeManager' => $storeManager + ]); + + $model->setData('image', 'myimage'); + + $result = $model->getImageUrl(); + + $this->assertEquals('http://www.example.com/catalog/category/myimage', $result); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Config/CatalogClone/Media/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Config/CatalogClone/Media/ImageTest.php index 6a0d695d71f39..fb648ba03253a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Config/CatalogClone/Media/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Config/CatalogClone/Media/ImageTest.php @@ -1,6 +1,6 @@ objectFactory = $this->getMockBuilder(\Magento\Framework\DataObject\Factory::class) @@ -90,12 +93,16 @@ protected function setUp() $this->buyRequest = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->disableOriginalConstructor() ->getMock(); + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->setMethods(['unserialize']) + ->getMockForAbstractClass(); $this->processor = new CustomOptionProcessor( $this->objectFactory, $this->productOptionFactory, $this->extensionFactory, - $this->customOptionFactory + $this->customOptionFactory, + $this->serializer ); } @@ -126,6 +133,9 @@ public function testConvertToBuyRequest() $this->assertSame($this->buyRequest, $this->processor->convertToBuyRequest($this->cartItem)); } + /** + * @covers \Magento\Catalog\Model\CustomOptions\CustomOptionProcessor::getOptions() + */ public function testProcessCustomOptions() { $optionId = 23; @@ -136,9 +146,12 @@ public function testProcessCustomOptions() ->method('getOptionByCode') ->with('info_buyRequest') ->willReturn($quoteItemOption); - $quoteItemOption->expects($this->once()) + $quoteItemOption->expects($this->any()) ->method('getValue') - ->willReturn('a:1:{s:7:"options";a:1:{i:' . $optionId . ';a:2:{i:0;s:1:"5";i:1;s:1:"6";}}} '); + ->willReturn('{"options":{"' . $optionId . '":["5","6"]}}'); + $this->serializer->expects($this->any()) + ->method('unserialize') + ->willReturn(json_decode($quoteItemOption->getValue(), true)); $this->customOptionFactory->expects($this->once()) ->method('create') ->willReturn($this->customOption); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php index d7a0fdb778d4c..f6fbbab61f8a0 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CustomOptions/CustomOptionTest.php @@ -1,6 +1,6 @@ flatIndexerMock = $this->getMockBuilder(\Magento\Catalog\Helper\Product\Flat\Indexer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resourceMock = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->scopeConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->tableDataMock = $this->getMockBuilder( + \Magento\Catalog\Model\Indexer\Product\Flat\TableDataInterface::class + )->disableOriginalConstructor()->getMockForAbstractClass(); + $this->connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->metadataPoolMock = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class) + ->disableOriginalConstructor() + ->getMock(); + $this->metadataMock = $this->getMockBuilder( + \Magento\Framework\EntityManager\EntityMetadataInterface::class + )->disableOriginalConstructor()->getMockForAbstractClass(); + $this->metadataMock->expects($this->any())->method('getLinkField')->willReturn('entity_id'); + + $this->flatTableBuilder = $objectManagerHelper->getObject( + \Magento\Catalog\Model\Indexer\Product\Flat\FlatTableBuilder::class, + [ + 'productIndexerHelper' => $this->flatIndexerMock, + 'resource' => $this->resourceMock, + 'config' => $this->scopeConfigMock, + 'storeManager' => $this->storeManagerMock, + 'tableData' => $this->tableDataMock, + '_connection' => $this->connectionMock + ] + ); + $objectManagerHelper->setBackwardCompatibleProperty( + $this->flatTableBuilder, + 'metadataPool', + $this->metadataPoolMock + ); + } + + public function testBuild() + { + $storeId = 1; + $changedIds = []; + $valueFieldSuffix = '_value'; + $tableDropSuffix = ''; + $fillTmpTables = true; + $tableName = 'catalog_product_entity'; + $attributeTable = 'catalog_product_entity_int'; + $temporaryTableName = 'catalog_product_entity_int_tmp_indexer'; + $temporaryValueTableName = 'catalog_product_entity_int_tmp_indexer_value'; + $linkField = 'entity_id'; + $statusId = 22; + $eavCustomField = 'space_weight'; + $eavCustomValueField = $eavCustomField . $valueFieldSuffix; + $this->flatIndexerMock->expects($this->once())->method('getAttributes')->willReturn([]); + $this->flatIndexerMock->expects($this->exactly(3))->method('getFlatColumns') + ->willReturnOnConsecutiveCalls([], [$eavCustomValueField => []], [$eavCustomValueField => []]); + $this->flatIndexerMock->expects($this->once())->method('getFlatIndexes')->willReturn([]); + $statusAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $eavCustomAttributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flatIndexerMock->expects($this->once())->method('getTablesStructure') + ->willReturn( + [ + 'catalog_product_entity' => [$linkField => $statusAttributeMock], + 'catalog_product_entity_int' => [ + $linkField => $statusAttributeMock, + $eavCustomField => $eavCustomAttributeMock + ] + ] + ); + $this->flatIndexerMock->expects($this->atLeastOnce())->method('getTable') + ->withConsecutive([$tableName], ['catalog_product_website']) + ->willReturnOnConsecutiveCalls($tableName, 'catalog_product_website'); + $this->flatIndexerMock->expects($this->once())->method('getAttribute') + ->with('status') + ->willReturn($statusAttributeMock); + $backendMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend::class) + ->disableOriginalConstructor() + ->getMock(); + $backendMock->expects($this->atLeastOnce())->method('getTable')->willReturn($attributeTable); + $statusAttributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn( + $backendMock + ); + $eavCustomAttributeMock->expects($this->atLeastOnce())->method('getBackend')->willReturn( + $backendMock + ); + $statusAttributeMock->expects($this->atLeastOnce())->method('getId')->willReturn($statusId); + $tableMock = $this->getMockBuilder(\Magento\Framework\DB\Ddl\Table::class) + ->disableOriginalConstructor() + ->getMock(); + $this->connectionMock->expects($this->any())->method('newTable')->willReturn($tableMock); + $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class) + ->disableOriginalConstructor() + ->getMock(); + $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($selectMock); + $selectMock->expects($this->once())->method('from')->with( + ['et' => 'catalog_product_entity_tmp_indexer'], + [$linkField, 'type_id', 'attribute_set_id'] + )->willReturnSelf(); + $selectMock->expects($this->atLeastOnce())->method('joinInner')->willReturnSelf(); + $selectMock->expects($this->exactly(3))->method('joinLeft') + ->withConsecutive( + [ + ['dstatus' => $attributeTable], + sprintf( + 'e.%s = dstatus.%s AND dstatus.store_id = %s AND dstatus.attribute_id = %s', + $linkField, + $linkField, + $storeId, + $statusId + ), + [] + ], + [ + $temporaryTableName, + "e.{$linkField} = {$temporaryTableName}.{$linkField}", + [$linkField, $eavCustomField] + ], + [ + $temporaryValueTableName, + "e.{$linkField} = {$temporaryValueTableName}.{$linkField}", + [$eavCustomValueField] + ] + )->willReturnSelf(); + $this->metadataPoolMock->expects($this->atLeastOnce())->method('getMetadata')->with(ProductInterface::class) + ->willReturn($this->metadataMock); + $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->storeManagerMock->expects($this->once())->method('getStore')->with($storeId)->willReturn($storeMock); + $this->flatTableBuilder->build($storeId, $changedIds, $valueFieldSuffix, $tableDropSuffix, $fillTmpTables); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php index 53d1a8fd004a0..097d70a5cf7cf 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php @@ -1,6 +1,6 @@ connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $table = $this->getMockBuilder(\Magento\Framework\DB\Ddl\Table::class) + ->disableOriginalConstructor() + ->getMock(); + $table->expects($this->once())->method('addColumn') + ->with('test', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER) + ->willReturnSelf(); + $tableName = 'test_table'; + $this->connectionMock->expects($this->once()) + ->method('newTable') + ->with($tableName) + ->willReturn($table); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + /** + * @var $builder \Magento\Catalog\Model\Indexer\Product\Flat\Table\Builder + */ + $builder = $objectManagerHelper->getObject( + \Magento\Catalog\Model\Indexer\Product\Flat\Table\Builder::class, + [ + 'connection' => $this->connectionMock, + 'tableName' => $tableName + ] + ); + $this->assertEquals($builder, $builder->addColumn('test', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/TableDataTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/TableDataTest.php index 0f47a675c8265..544bd865a5073 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/TableDataTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/TableDataTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); $localeFormatMock = $this->getMock(\Magento\Framework\Locale\FormatInterface::class, [], [], '', false); $groupManagement = $this->getMock(\Magento\Customer\Api\GroupManagementInterface::class, [], [], '', false); - $metadataPool = $this->getMock(\Magento\Framework\EntityManager\MetadataPool::class, [], [], '', false); + $scopeOverriddenValue = $this->getMock( + \Magento\Catalog\Model\Attribute\ScopeOverriddenValue::class, + [], + [], + '', + false + ); $this->_model = $this->getMockForAbstractClass( \Magento\Catalog\Model\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice::class, [ @@ -50,7 +56,7 @@ protected function setUp() 'localeFormat' => $localeFormatMock, 'catalogProductType' => $productTypeMock, 'groupManagement' => $groupManagement, - 'metadataPool' => $metadataPool + 'scopeOverriddenValue' => $scopeOverriddenValue ] ); $resource = $this->getMock(\StdClass::class, ['getMainTable']); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/Media/EntryConverterPoolTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/Media/EntryConverterPoolTest.php index 07b4b10834c71..827fe62fd6002 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/Media/EntryConverterPoolTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/Media/EntryConverterPoolTest.php @@ -1,6 +1,6 @@ getMockForAbstractClass( - \Magento\Framework\App\ScopeResolverInterface::class, - [], - '', - false - ); - $localeResolver = $this->getMockForAbstractClass( - \Magento\Framework\Locale\ResolverInterface::class, - [], - '', - false - ); - $currencyFactory = $this->getMock(\Magento\Directory\Model\CurrencyFactory::class, [], [], '', false); - $localeFormat = $objectHelper->getObject( - \Magento\Framework\Locale\Format::class, - [ - 'scopeResolver' => $scopeResolver, - 'localeResolver' => $localeResolver, - 'currencyFactory' => $currencyFactory, - ] - ); - - // the model we are testing + $localeFormat = $objectHelper->getObject(\Magento\Framework\Locale\Format::class); + $this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) + ->getMockForAbstractClass(); + $this->currencyFactory = $this->getMockBuilder(\Magento\Directory\Model\CurrencyFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor()->getMock(); $this->model = $objectHelper->getObject( \Magento\Catalog\Model\Product\Attribute\Backend\Price::class, - ['localeFormat' => $localeFormat] - ); - - $attribute = $this->getMockForAbstractClass( - \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class, - [], - '', - false + [ + 'localeFormat' => $localeFormat, + 'storeManager' => $this->storeManager, + 'currencyFactory' => $this->currencyFactory + ] ); - $this->model->setAttribute($attribute); + $this->attribute = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods(['getAttributeCode', 'isScopeWebsite']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->model->setAttribute($this->attribute); } /** @@ -111,4 +111,71 @@ public function dataProviderValidateForFailure() 'negative Lebanon' => ['-1 234'], ]; } + + public function testAfterSaveWithDifferentStores() + { + $newPrice = '9.99'; + $attributeCode = 'price'; + $defaultStoreId = 0; + $allStoreIds = [1, 2, 3]; + $object = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)->disableOriginalConstructor()->getMock(); + $object->expects($this->any())->method('getData')->with($attributeCode)->willReturn($newPrice); + $object->expects($this->any())->method('getOrigData')->with($attributeCode)->willReturn('7.77'); + $object->expects($this->any())->method('getStoreId')->willReturn($defaultStoreId); + $object->expects($this->never())->method('getStoreIds'); + $object->expects($this->never())->method('getWebsiteStoreIds'); + $this->attribute->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + $this->attribute->expects($this->any())->method('isScopeWebsite') + ->willReturn(\Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE); + $this->storeManager->expects($this->never())->method('getStore'); + + $object->expects($this->any())->method('addAttributeUpdate')->withConsecutive( + [ + $this->equalTo($attributeCode), + $this->equalTo($newPrice), + $this->equalTo($allStoreIds[0]) + ], + [ + $this->equalTo($attributeCode), + $this->equalTo($newPrice), + $this->equalTo($allStoreIds[1]) + ], + [ + $this->equalTo($attributeCode), + $this->equalTo($newPrice), + $this->equalTo($allStoreIds[2]) + ] + ); + $this->assertEquals($this->model, $this->model->afterSave($object)); + } + + public function testAfterSaveWithOldPrice() + { + $attributeCode = 'price'; + + $object = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)->disableOriginalConstructor()->getMock(); + $object->expects($this->any())->method('getData')->with($attributeCode)->willReturn('7.77'); + $object->expects($this->any())->method('getOrigData')->with($attributeCode)->willReturn('7.77'); + $this->attribute->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + $this->attribute->expects($this->any())->method('getIsGlobal') + ->willReturn(\Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE); + + $object->expects($this->never())->method('addAttributeUpdate'); + $this->assertEquals($this->model, $this->model->afterSave($object)); + } + + public function testAfterSaveWithGlobalPrice() + { + $attributeCode = 'price'; + + $object = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)->disableOriginalConstructor()->getMock(); + $object->expects($this->any())->method('getData')->with($attributeCode)->willReturn('9.99'); + $object->expects($this->any())->method('getOrigData')->with($attributeCode)->willReturn('7.77'); + $this->attribute->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + $this->attribute->expects($this->any())->method('getIsGlobal') + ->willReturn(\Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL); + + $object->expects($this->never())->method('addAttributeUpdate'); + $this->assertEquals($this->model, $this->model->afterSave($object)); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php index ec9cb624db79a..74a42fa2cc845 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php @@ -1,6 +1,6 @@ getStockData(); $this->assertEquals(0, $stockData['qty']); } + + public function testBeforeSaveNoStockData() + { + $object = new \Magento\Framework\DataObject( + [ + self::ATTRIBUTE_NAME => ['is_in_stock' => 1, 'qty' => 0] + ] + ); + + $this->model->beforeSave($object); + $this->assertNull($object->getStockData()); + $this->assertNull($object->getData(self::ATTRIBUTE_NAME)); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/WeightTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/WeightTest.php index 0ca0cdf7818b4..7d1bf213b7e34 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/WeightTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/WeightTest.php @@ -1,6 +1,6 @@ model->save($attributeMock); } + + public function testSaveDoesNotSaveAttributeOptionsIfOptionsAreAbsentInPayload() + { + $attributeId = 1; + $attributeCode = 'existing_attribute_code'; + $attributeMock = $this->getMock(Attribute::class, [], [], '', false); + $attributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + $attributeMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId); + + $existingModelMock = $this->getMock(Attribute::class, [], [], '', false); + $existingModelMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + $existingModelMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId); + + $this->eavAttributeRepositoryMock->expects($this->any()) + ->method('get') + ->with(ProductAttributeInterface::ENTITY_TYPE_CODE, $attributeCode) + ->willReturn($existingModelMock); + + // Attribute code must not be changed after attribute creation + $attributeMock->expects($this->once())->method('setAttributeCode')->with($attributeCode); + $this->attributeResourceMock->expects($this->once())->method('save')->with($attributeMock); + $this->optionManagementMock->expects($this->never())->method('add'); + + $this->model->save($attributeMock); + } + + public function testSaveSavesDefaultFrontendLabelIfItIsPresentInPayload() + { + $labelMock = $this->getMock(AttributeFrontendLabelInterface::class); + $labelMock->expects($this->any())->method('getStoreId')->willReturn(1); + $labelMock->expects($this->any())->method('getLabel')->willReturn('Store Scope Label'); + + $attributeId = 1; + $attributeCode = 'existing_attribute_code'; + $attributeMock = $this->getMock(Attribute::class, [], [], '', false); + $attributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + $attributeMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId); + $attributeMock->expects($this->any())->method('getDefaultFrontendLabel')->willReturn('Default Label'); + $attributeMock->expects($this->any())->method('getFrontendLabels')->willReturn([$labelMock]); + $attributeMock->expects($this->any())->method('getOptions')->willReturn([]); + + + $existingModelMock = $this->getMock(Attribute::class, [], [], '', false); + $existingModelMock->expects($this->any())->method('getAttributeId')->willReturn($attributeId); + $existingModelMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode); + + $this->eavAttributeRepositoryMock->expects($this->any()) + ->method('get') + ->with(ProductAttributeInterface::ENTITY_TYPE_CODE, $attributeCode) + ->willReturn($existingModelMock); + + $attributeMock->expects($this->once()) + ->method('setDefaultFrontendLabel') + ->with( + [ + 0 => 'Default Label', + 1 => 'Store Scope Label' + ] + ); + $this->attributeResourceMock->expects($this->once())->method('save')->with($attributeMock); + + $this->model->save($attributeMock); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/SetManagementTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/SetManagementTest.php index 25553562d2a0b..6d70c1611cd5c 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/SetManagementTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/SetManagementTest.php @@ -1,7 +1,7 @@ storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class); $this->storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); $this->cacheConfig = $this->getMock(\Magento\Framework\App\Cache\Type\Config::class, [], [], '', false); $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->countryOfManufacture = $this->objectManagerHelper->getObject( + \Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture::class, + [ + 'storeManager' => $this->storeManagerMock, + 'configCacheType' => $this->cacheConfig, + ] + ); + + $this->serializerMock = $this->getMock(SerializerInterface::class, [], [], '', false); + $this->objectManagerHelper->setBackwardCompatibleProperty( + $this->countryOfManufacture, + 'serializer', + $this->serializerMock + ); } /** @@ -51,15 +75,10 @@ public function testGetAllOptions($cachedDataSrl, $cachedDataUnsrl) ->method('load') ->with($this->equalTo('COUNTRYOFMANUFACTURE_SELECT_STORE_store_code')) ->will($this->returnValue($cachedDataSrl)); - - $countryOfManufacture = $this->objectManagerHelper->getObject( - \Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture::class, - [ - 'storeManager' => $this->storeManagerMock, - 'configCacheType' => $this->cacheConfig, - ] - ); - $this->assertEquals($cachedDataUnsrl, $countryOfManufacture->getAllOptions()); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn($cachedDataUnsrl); + $this->assertEquals($cachedDataUnsrl, $this->countryOfManufacture->getAllOptions()); } /** @@ -71,7 +90,7 @@ public function testGetAllOptionsDataProvider() { return [ - ['cachedDataSrl' => 'a:1:{s:3:"key";s:4:"data";}', 'cachedDataUnsrl' => ['key' => 'data']] + ['cachedDataSrl' => json_encode(['key' => 'data']), 'cachedDataUnsrl' => ['key' => 'data']] ]; } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php index 8362fc8a76180..2e9ea0f698514 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php @@ -1,6 +1,6 @@ productRepositoryMock = $this->getMock(\Magento\Catalog\Api\ProductRepositoryInterface::class); $this->contentValidatorMock = $this->getMock(\Magento\Framework\Api\ImageContentValidatorInterface::class); - $this->productMock = $this->getMock( + $this->productMock = $this->getMock( \Magento\Catalog\Model\Product::class, [ 'setStoreId', @@ -115,7 +115,7 @@ public function testCreateWithCannotSaveException() public function testCreate() { $productSku = 'mediaProduct'; - $entryContentMock = $this->getMock( + $entryContentMock = $this->getMock( \Magento\Framework\Api\Data\ImageContentInterface::class ); $this->mediaGalleryEntryMock->expects($this->any())->method('getContent')->willReturn($entryContentMock); @@ -153,8 +153,8 @@ public function testUpdateWithNonExistingImage() $entryId = 42; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); - $existingEntryMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + $existingEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); $existingEntryMock->expects($this->once())->method('getId')->willReturn(43); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') @@ -174,8 +174,8 @@ public function testUpdateWithCannotSaveException() $entryId = 42; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); - $existingEntryMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + $existingEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); $existingEntryMock->expects($this->once())->method('getId')->willReturn($entryId); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') @@ -191,18 +191,33 @@ public function testUpdate() $productSku = 'testProduct'; $entryMock = $this->getMock(\Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class); $entryId = 42; + $entrySecondId = 43; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); - $existingEntryMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + $existingEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); + $existingSecondEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + ); + $existingEntryMock->expects($this->once())->method('getId')->willReturn($entryId); + $existingEntryMock->expects($this->once())->method('getTypes')->willReturn(['small_image']); + $existingEntryMock->expects($this->once())->method('setTypes')->with(['small_image']); + $existingSecondEntryMock->expects($this->once())->method('getId')->willReturn($entrySecondId); + $existingSecondEntryMock->expects($this->once())->method('getTypes')->willReturn(['image']); + $existingSecondEntryMock->expects($this->once())->method('setTypes')->with([]); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') - ->willReturn([$existingEntryMock]); - $entryMock->expects($this->once())->method('getId')->willReturn($entryId); + ->willReturn([$existingEntryMock, $existingSecondEntryMock]); + + $entryMock->expects($this->exactly(2))->method('getId')->willReturn($entryId); + $entryMock->expects($this->once())->method('getFile')->willReturn("base64"); + $entryMock->expects($this->once())->method('setId')->with(null); + $entryMock->expects($this->exactly(2))->method('getTypes')->willReturn(['image']); $this->productMock->expects($this->once())->method('setMediaGalleryEntries') - ->willReturn([$entryMock]); + ->with([$entryMock, $existingSecondEntryMock]) + ->willReturnSelf(); $this->productRepositoryMock->expects($this->once())->method('save')->with($this->productMock); $this->assertTrue($this->model->update($productSku, $entryMock)); } @@ -217,8 +232,8 @@ public function testRemoveWithNonExistingImage() $entryId = 42; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); - $existingEntryMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + $existingEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); $existingEntryMock->expects($this->once())->method('getId')->willReturn(43); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') @@ -232,8 +247,8 @@ public function testRemove() $entryId = 42; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); - $existingEntryMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + $existingEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); $existingEntryMock->expects($this->once())->method('getId')->willReturn(42); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') @@ -267,8 +282,8 @@ public function testGetWithNonExistingImage() $imageId = 43; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); - $existingEntryMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + $existingEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); $existingEntryMock->expects($this->once())->method('getId')->willReturn(44); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') @@ -282,8 +297,8 @@ public function testGet() $imageId = 42; $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku) ->willReturn($this->productMock); - $existingEntryMock = $this->getMock( - \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class + $existingEntryMock = $this->getMock( + \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface::class ); $existingEntryMock->expects($this->once())->method('getId')->willReturn(42); $this->productMock->expects($this->once())->method('getMediaGalleryEntries') diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/MimeTypeExtensionMapTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/MimeTypeExtensionMapTest.php index ebf351da74102..8ec55bcec098a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/MimeTypeExtensionMapTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Gallery/MimeTypeExtensionMapTest.php @@ -1,7 +1,7 @@ getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + + $productMock->expects($this->exactly($setDataExpectsCalls)) + ->method('setData') + ->with($setDataArgument, 'no_selection'); + + $this->mediaConfig->expects($this->once()) + ->method('getMediaAttributeCodes') + ->willReturn(['image', 'small_image']); + + $this->assertSame($this->model, $this->model->clearMediaAttribute($productMock, $mediaAttribute)); + } + + /** + * @return array + */ + public function clearMediaAttributeDataProvider() + { + return [ + [ + 'setDataExpectsCalls' => 1, + 'setDataArgument' => 'image', + 'mediaAttribute' => 'image', + ], + [ + 'setDataExpectsCalls' => 1, + 'setDataArgument' => 'image', + 'mediaAttribute' => ['image'], + ], + [ + 'setDataExpectsCalls' => 0, + 'setDataArgument' => null, + 'mediaAttribute' => 'some_image', + ], + [ + 'setDataExpectsCalls' => 0, + 'setDataArgument' => null, + 'mediaAttribute' => ['some_image'], + ], + ]; + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Image/CacheTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Image/CacheTest.php index de60264c33163..f12638ac40c8f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Image/CacheTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Image/CacheTest.php @@ -1,6 +1,6 @@ context = $this->getMock(\Magento\Framework\Model\Context::class, [], [], '', false); @@ -99,7 +119,6 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods(['create', 'isFile', 'isExist', 'getAbsolutePath']) ->getMock(); - $this->mediaDirectory->expects($this->once())->method('create')->will($this->returnValue(true)); $this->filesystem = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); $this->filesystem->expects($this->once())->method('getDirectoryWrite') @@ -110,20 +129,49 @@ protected function setUp() $this->fileSystem = $this->getMock(\Magento\Framework\View\FileSystem::class, [], [], '', false); $this->scopeConfigInterface = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); + $context = $this->getMockBuilder(\Magento\Framework\Model\Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->image = new \Magento\Catalog\Model\Product\Image( + $context, + $this->registry, + $this->storeManager, + $this->config, + $this->coreFileHelper, + $this->filesystem, + $this->factory, + $this->repository, + $this->fileSystem, + $this->scopeConfigInterface + ); + //Settings for backward compatible property $objectManagerHelper = new ObjectManagerHelper($this); - $this->image = $objectManagerHelper->getObject( - \Magento\Catalog\Model\Product\Image::class, - [ - 'registry' => $this->registry, - 'storeManager' => $this->storeManager, - 'catalogProductMediaConfig' => $this->config, - 'coreFileStorageDatabase' => $this->coreFileHelper, - 'filesystem' => $this->filesystem, - 'imageFactory' => $this->factory, - 'assetRepo' => $this->repository, - 'viewFileSystem' => $this->fileSystem, - 'scopeConfig' => $this->scopeConfigInterface - ] + $this->imageAsset = $this->getMockBuilder(\Magento\Framework\View\Asset\LocalInterface::class) + ->getMockForAbstractClass(); + $objectManagerHelper->setBackwardCompatibleProperty( + $this->image, + 'imageAsset', + $this->imageAsset + ); + + $this->viewAssetImageFactory = $this->getMockBuilder(ImageFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $objectManagerHelper->setBackwardCompatibleProperty( + $this->image, + 'viewAssetImageFactory', + $this->viewAssetImageFactory + ); + + $this->viewAssetPlaceholderFactory = $this->getMockBuilder(PlaceholderFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $objectManagerHelper->setBackwardCompatibleProperty( + $this->image, + 'viewAssetPlaceholderFactory', + $this->viewAssetPlaceholderFactory ); } @@ -177,18 +225,39 @@ public function testSetGetBaseFile() $absolutePath = dirname(dirname(__DIR__)) . '/_files/catalog/product/somefile.png'; $this->mediaDirectory->expects($this->any())->method('getAbsolutePath') ->will($this->returnValue($absolutePath)); + $this->viewAssetImageFactory->expects($this->any()) + ->method('create') + ->with( + [ + 'miscParams' => [ + 'image_type' => null, + 'image_height' => null, + 'image_width' => null, + 'keep_aspect_ratio' => 'proportional', + 'keep_frame' => 'frame', + 'keep_transparency' => 'transparency', + 'constrain_only' => 'doconstrainonly', + 'background' => 'ffffff', + 'angle' => null, + 'quality' => 80, + ], + 'filePath' => '/somefile.png', + ] + ) + ->willReturn($this->imageAsset); + $this->viewAssetPlaceholderFactory->expects($this->never())->method('create'); + + $this->imageAsset->expects($this->any())->method('getSourceFile')->willReturn('catalog/product/somefile.png'); $this->image->setBaseFile('/somefile.png'); $this->assertEquals('catalog/product/somefile.png', $this->image->getBaseFile()); - $this->assertEquals( - 'catalog/product/cache/1//beff4985b56e3afdbeabfc89641a4582/somefile.png', - $this->image->getNewFile() - ); } public function testSetBaseNoSelectionFile() { - $this->image->setBaseFile('/no_selection'); - $this->assertTrue($this->image->getNewFile()); + $this->viewAssetPlaceholderFactory->expects($this->once())->method('create')->willReturn($this->imageAsset); + $this->imageAsset->expects($this->any())->method('getSourceFile')->willReturn('Default Placeholder Path'); + $this->image->setBaseFile('no_selection'); + $this->assertEquals('Default Placeholder Path', $this->image->getBaseFile()); } public function testSetGetImageProcessor() @@ -284,45 +353,45 @@ public function testSaveFile() )->disableOriginalConstructor()->getMock(); $this->image->setImageProcessor($imageProcessor); $this->coreFileHelper->expects($this->once())->method('saveFile')->will($this->returnValue(true)); - $absolutePath = dirname(dirname(__DIR__)) . '/_files/catalog/product/somefile.png'; - $this->mediaDirectory->expects($this->once())->method('getAbsolutePath') - ->will($this->returnValue($absolutePath)); $this->image->saveFile(); } public function testSaveFileNoSelection() { - $this->testSetBaseNoSelectionFile(); + $imageProcessor = $this->getMockBuilder( + \Magento\Framework\Image::class + )->disableOriginalConstructor()->getMock(); + $this->image->setImageProcessor($imageProcessor); $this->assertSame($this->image, $this->image->saveFile()); } public function testGetUrl() { $this->testSetGetBaseFile(); - $url = $this->image->getUrl(); - $this->assertEquals( - 'http://magento.com/media/catalog/product/cache/1//beff4985b56e3afdbeabfc89641a4582/somefile.png', - $url - ); + $this->imageAsset->expects($this->any())->method('getUrl')->will($this->returnValue('url of exist image')); + $this->assertEquals('url of exist image', $this->image->getUrl()); } public function testGetUrlNoSelection() { - $this->testSetBaseNoSelectionFile(); - $this->repository->expects($this->once())->method('getUrl')->will($this->returnValue('someurl')); - $this->assertEquals('someurl', $this->image->getUrl()); + $this->viewAssetPlaceholderFactory->expects($this->once())->method('create')->willReturn($this->imageAsset); + $this->imageAsset->expects($this->any())->method('getUrl')->will($this->returnValue('Default Placeholder URL')); + $this->image->setBaseFile('no_selection'); + $this->assertEquals('Default Placeholder URL', $this->image->getUrl()); } public function testSetGetDestinationSubdir() { - $this->image->setDestinationSubdir('somesubdir'); - $this->assertEquals('somesubdir', $this->image->getDestinationSubdir()); + $this->image->setDestinationSubdir('image_type'); + $this->assertEquals('image_type', $this->image->getDestinationSubdir()); } public function testIsCached() { $this->testSetGetBaseFile(); + $absolutePath = dirname(dirname(__DIR__)) . '/_files/catalog/product/watermark/somefile.png'; + $this->imageAsset->expects($this->any())->method('getPath')->willReturn($absolutePath); $this->assertTrue($this->image->isCached()); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Initialization/Helper/ProductLinksTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Initialization/Helper/ProductLinksTest.php index 34cb5c81a1291..681e662c69ccd 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Initialization/Helper/ProductLinksTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Initialization/Helper/ProductLinksTest.php @@ -1,6 +1,6 @@ getMock( - \Magento\Catalog\Model\ResourceModel\Product\Option\CollectionFactory::class, - ['create'], - [], - '', - false - ); + $this->optionCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); $metadataPool = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class) ->disableOriginalConstructor() ->getMock(); @@ -96,7 +100,7 @@ protected function setUp() $this->optionRepository, [ 'optionFactory' => $optionFactory, - 'optionCollectionFactory' => $optionCollectionFactory, + 'collectionFactory' => $this->optionCollectionFactory, 'metadataPool' => $metadataPool ] ); @@ -240,4 +244,75 @@ private function setProperties($object, $properties = []) } } } + + /** + * @expectedException \Magento\Framework\Exception\CouldNotSaveException + * @expectedExceptionMessage ProductSku should be specified + */ + public function testSaveCouldNotSaveException() + { + $this->optionMock->expects($this->once())->method('getProductSku')->willReturn(null); + $this->optionRepository->save($this->optionMock); + } + + /** + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + */ + public function testSaveNoSuchEntityException() + { + $productSku = 'simple_product'; + $optionId = 1; + $productOptionId = 2; + $this->optionMock->expects($this->once())->method('getProductSku')->willReturn($productSku); + $this->productRepositoryMock + ->expects($this->once()) + ->method('get') + ->with($productSku) + ->willReturn($this->productMock); + $productOption = clone $this->optionMock; + $this->optionMock->expects($this->any())->method('getOptionId')->willReturn($optionId); + $productOption->expects($this->any())->method('getOptionId')->willReturn($productOptionId); + $this->productMock->expects($this->once())->method('getOptions')->willReturn([$productOption]); + $this->optionRepository->save($this->optionMock); + } + + public function testSave() + { + $productSku = 'simple_product'; + $optionId = 1; + $originalValue1 = $this->getMockBuilder(\Magento\Catalog\Model\Product\Option::class) + ->disableOriginalConstructor() + ->getMock(); + $originalValue2 = clone $originalValue1; + $originalValue3 = clone $originalValue1; + + $originalValue1->expects($this->at(0))->method('getData')->with('option_type_id')->willReturn(10); + $originalValue1->expects($this->once())->method('setData')->with('is_delete', 1); + $originalValue2->expects($this->once())->method('getData')->with('option_type_id')->willReturn(4); + $originalValue3->expects($this->once())->method('getData')->with('option_type_id')->willReturn(5); + + $this->optionMock->expects($this->once())->method('getProductSku')->willReturn($productSku); + $this->productRepositoryMock + ->expects($this->once()) + ->method('get') + ->with($productSku) + ->willReturn($this->productMock); + $this->optionMock->expects($this->any())->method('getOptionId')->willReturn($optionId); + $this->productMock->expects($this->once())->method('getOptions')->willReturn([]); + $this->optionMock->expects($this->once())->method('getData')->with('values')->willReturn([ + ['option_type_id' => 4], + ['option_type_id' => 5] + ]); + $optionCollection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Option\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $optionCollection->expects($this->once())->method('getProductOptions')->willReturn([$this->optionMock]); + $this->optionCollectionFactory->expects($this->once())->method('create')->willReturn($optionCollection); + $this->optionMock->expects($this->once())->method('getValues')->willReturn([ + $originalValue1, + $originalValue2, + $originalValue3 + ]); + $this->assertEquals($this->optionMock, $this->optionRepository->save($this->optionMock)); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/SaveHandlerTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/SaveHandlerTest.php new file mode 100644 index 0000000000000..cf29f44550f1f --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/SaveHandlerTest.php @@ -0,0 +1,72 @@ +entity = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->getMock(); + $this->optionMock = $this->getMockBuilder(Option::class) + ->disableOriginalConstructor() + ->getMock(); + $this->optionRepository = $this->getMockBuilder(Repository::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new SaveHandler($this->optionRepository); + } + + public function testExecute() + { + $this->optionMock->expects($this->any())->method('getOptionId')->willReturn(5); + $this->entity->expects($this->once())->method('getOptions')->willReturn([$this->optionMock]); + + $secondOptionMock = $this->getMockBuilder(Option::class) + ->disableOriginalConstructor() + ->getMock(); + $secondOptionMock->expects($this->once())->method('getOptionId')->willReturn(6); + + $this->optionRepository + ->expects($this->once()) + ->method('getProductOptions') + ->with($this->entity) + ->willReturn([$this->optionMock, $secondOptionMock]); + + $this->optionRepository->expects($this->once())->method('delete'); + $this->optionRepository->expects($this->once())->method('save')->with($this->optionMock); + + $this->assertEquals($this->entity, $this->model->execute($this->entity)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FactoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FactoryTest.php index 1b66800ca8c01..d9b381ec3a365 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FactoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FactoryTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->rootDirectory = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\ReadInterface::class) + $this->filesystemMock = $this->getMockBuilder(Filesystem::class) ->disableOriginalConstructor() - ->setMethods(['isFile', 'isReadable', 'getAbsolutePath']) - ->getMockForAbstractClass(); + ->getMock(); + + $this->rootDirectory = $this->getMockBuilder(ReadInterface::class) + ->getMock(); + + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->with(DirectoryList::MEDIA, DriverPool::FILE) + ->willReturn($this->rootDirectory); + + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->urlBuilder = $this->getMockBuilder(\Magento\Catalog\Model\Product\Option\UrlBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class) + ->disableOriginalConstructor() + ->getMock(); $this->coreFileStorageDatabase = $this->getMock( \Magento\MediaStorage\Helper\File\Storage\Database::class, @@ -48,24 +98,65 @@ protected function getFileObject() return $this->objectManager->getObject( \Magento\Catalog\Model\Product\Option\Type\File::class, [ - 'saleableItem' => $this->rootDirectory, - 'priceCurrency' => $this->coreFileStorageDatabase + 'filesystem' => $this->filesystemMock, + 'coreFileStorageDatabase' => $this->coreFileStorageDatabase, + 'serializer' => $this->serializer, + 'urlBuilder' => $this->urlBuilder, + 'escaper' => $this->escaper ] ); } + public function testGetCustomizedView() + { + $fileObject = $this->getFileObject(); + $optionInfo = ['option_value' => 'some serialized data']; + + $dataAfterSerialize = ['some' => 'array']; + + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with('some serialized data') + ->willReturn($dataAfterSerialize); + + $this->urlBuilder->expects($this->once()) + ->method('getUrl') + ->willReturn('someUrl'); + + $this->escaper->expects($this->once()) + ->method('escapeHtml') + ->willReturn('string'); + + $this->assertEquals( + 'string ', + $fileObject->getCustomizedView($optionInfo) + ); + } + public function testCopyQuoteToOrder() { - $optionMock = $this->getMockBuilder( - \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class - )->disableOriginalConstructor()->setMethods(['getValue'])->getMockForAbstractClass(); + $optionMock = $this->getMockBuilder(OptionInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getValue']) + ->getMockForAbstractClass(); $quotePath = '/quote/path/path/uploaded.file'; $orderPath = '/order/path/path/uploaded.file'; + $quoteValue = "{\"quote_path\":\"$quotePath\",\"order_path\":\"$orderPath\"}"; + + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($quoteValue) + ->willReturnCallback( + function ($value) { + return json_decode($value, true); + } + ); + $optionMock->expects($this->any()) ->method('getValue') - ->will($this->returnValue(['quote_path' => $quotePath, 'order_path' => $orderPath])); + ->will($this->returnValue($quoteValue)); $this->rootDirectory->expects($this->any()) ->method('isFile') @@ -93,4 +184,55 @@ public function testCopyQuoteToOrder() $fileObject->copyQuoteToOrder() ); } + + public function testGetFormattedOptionValue() + { + $resultValue = ['result']; + $optionValue = json_encode($resultValue); + $urlParameter = 'parameter'; + + $fileObject = $this->getFileObject(); + $fileObject->setCustomOptionUrlParams($urlParameter); + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($optionValue) + ->willReturn($resultValue); + + $resultValue['url'] = [ + 'route' => 'sales/download/downloadCustomOption', + 'params' => $fileObject->getCustomOptionUrlParams() + ]; + + $this->serializer->expects($this->once()) + ->method('serialize') + ->with($resultValue) + ->willReturn(json_encode($resultValue)); + + $option = $this->getMockBuilder(\Magento\Quote\Model\Quote\Item\Option::class) + ->setMethods(['setValue']) + ->disableOriginalConstructor() + ->getMock(); + + $option->expects($this->once()) + ->method('setValue') + ->with(json_encode($resultValue)); + + $fileObject->setConfigurationItemOption($option); + + $fileObject->getFormattedOptionValue($optionValue); + } + + public function testPrepareOptionValueForRequest() + { + $optionValue = 'string'; + $resultValue = ['result']; + $fileObject = $this->getFileObject(); + + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($optionValue) + ->willReturn($resultValue); + + $this->assertEquals($resultValue, $fileObject->prepareOptionValueForRequest($optionValue)); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/UrlBuilderTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/UrlBuilderTest.php index 9b0e1e1627454..0d543d16286d7 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/UrlBuilderTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/UrlBuilderTest.php @@ -1,6 +1,6 @@ pricePersistenceFactory = $this->getMock( + \Magento\Catalog\Model\Product\Price\PricePersistenceFactory::class, + ['create'], + [], + '', + false + ); + $this->pricePersistence = $this->getMock( + \Magento\Catalog\Model\Product\Price\PricePersistence::class, + ['get', 'retrieveSkuById', 'update', 'getEntityLinkField'], + [], + '', + false + ); + $this->basePriceInterfaceFactory = $this->getMock( + \Magento\Catalog\Api\Data\BasePriceInterfaceFactory::class, + ['create'], + [], + '', + false + ); + $this->basePriceInterface = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\BasePriceInterface::class, + [], + '', + false, + true, + true, + ['setSku', 'setPrice', 'setStoreId', 'getSku', 'getPrice', 'getStoreId'] + ); + $this->productIdLocator = $this->getMockForAbstractClass( + \Magento\Catalog\Model\ProductIdLocatorInterface::class, + [], + '', + false, + true, + true, + ['retrieveProductIdsBySkus'] + ); + $this->storeRepository = $this->getMockForAbstractClass( + \Magento\Store\Api\StoreRepositoryInterface::class, + [], + '', + false, + true, + true, + ['getById'] + ); + $this->productRepository = $this->getMockForAbstractClass( + \Magento\Catalog\Api\ProductRepositoryInterface::class, + [], + '', + false, + true, + true, + ['get'] + ); + $this->product = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\ProductInterface::class, + [], + '', + false, + true, + true, + ['getPriceType'] + ); + $this->invalidSkuChecker = $this->getMockForAbstractClass( + \Magento\Catalog\Model\Product\Price\InvalidSkuChecker::class, + [], + '', + false, + true, + true, + ['retrieveInvalidSkuList'] + ); + $this->validationResult = $this->getMockForAbstractClass( + \Magento\Catalog\Model\Product\Price\Validation\Result::class, + [], + '', + false, + true, + true, + ['getFailedRowIds', 'getFailedItems'] + ); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManager->getObject( + \Magento\Catalog\Model\Product\Price\BasePriceStorage::class, + [ + 'pricePersistenceFactory' => $this->pricePersistenceFactory, + 'basePriceInterfaceFactory' => $this->basePriceInterfaceFactory, + 'productIdLocator' => $this->productIdLocator, + 'storeRepository' => $this->storeRepository, + 'productRepository' => $this->productRepository, + 'invalidSkuChecker' => $this->invalidSkuChecker, + 'validationResult' => $this->validationResult, + 'allowedProductTypes' => ['simple', 'virtual', 'bundle', 'downloadable'], + ] + ); + } + + /** + * Test get method. + * + * @return void + */ + public function testGet() + { + $skus = ['sku_1', 'sku_2']; + $rawPrices = [ + [ + 'row_id' => 1, + 'value' => 15, + 'store_id' => 1 + ], + [ + 'row_id' => 2, + 'value' => 35, + 'store_id' => 1 + ] + ]; + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'price']) + ->willReturn($this->pricePersistence); + $this->pricePersistence->expects($this->once())->method('get')->with($skus)->willReturn($rawPrices); + $this->pricePersistence->expects($this->atLeastOnce())->method('getEntityLinkField')->willReturn('row_id'); + $this->basePriceInterfaceFactory + ->expects($this->exactly(2)) + ->method('create') + ->willReturn($this->basePriceInterface); + $this->pricePersistence + ->expects($this->exactly(2)) + ->method('retrieveSkuById') + ->willReturnOnConsecutiveCalls('sku_1', 'sku_2'); + $this->basePriceInterface + ->expects($this->exactly(2)) + ->method('setSku') + ->withConsecutive(['sku_1'], ['sku_2']) + ->willReturnSelf(); + $this->basePriceInterface + ->expects($this->exactly(2)) + ->method('setPrice') + ->withConsecutive([15], [35]) + ->willReturnSelf(); + $this->basePriceInterface + ->expects($this->exactly(2)) + ->method('setStoreId') + ->withConsecutive([1], [1]) + ->willReturnSelf(); + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->model->get($skus); + } + + /** + * Test get method with exception. + * + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + * @expectedExceptionMessage Requested products don't exist: sku_1, sku_2 + */ + public function testGetWithException() + { + $skus = ['sku_1', 'sku_2']; + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn($skus); + $this->model->get($skus); + } + + /** + * Test update method. + * + * @return void + */ + public function testUpdate() + { + $store = $this->getMockForAbstractClass( + \Magento\Store\Api\Data\StoreInterface::class, + [], + '', + false + ); + $sku = 'sku_1'; + $idsBySku = [ + 'sku_1' => + [ + 1 => [ + $this->basePriceInterface + ] + ] + ]; + $this->basePriceInterface->expects($this->exactly(5))->method('getSku')->willReturn($sku); + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->validationResult->expects($this->once())->method('getFailedRowIds')->willReturn([]); + $this->productIdLocator + ->expects($this->exactly(1)) + ->method('retrieveProductIdsBySkus')->with([$sku]) + ->willReturn($idsBySku); + $this->basePriceInterface->expects($this->exactly(3))->method('getPrice')->willReturn(15); + $this->basePriceInterface->expects($this->exactly(2))->method('getStoreId')->willReturn(1); + $this->pricePersistence->expects($this->atLeastOnce())->method('getEntityLinkField')->willReturn('row_id'); + $this->storeRepository->expects($this->once())->method('getById')->with(1)->willReturn($store); + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'price']) + ->willReturn($this->pricePersistence); + $formattedPrices = [ + [ + 'store_id' => 1, + 'row_id' => 1, + 'value' => 15 + ] + ]; + $this->pricePersistence->expects($this->once())->method('update')->with($formattedPrices); + $this->validationResult->expects($this->any())->method('getFailedItems')->willReturn([]); + $this->assertEquals([], $this->model->update([1 => $this->basePriceInterface])); + } + + /** + * Test update method without SKU. + * + * @return void + */ + public function testUpdateWithoutSku() + { + $this->basePriceInterface->expects($this->exactly(3))->method('getSku')->willReturn(null); + $this->validationResult->expects($this->once())->method('getFailedRowIds')->willReturn([0 => 0]); + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'price']) + ->willReturn($this->pricePersistence); + $priceUpdateResult = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\PriceUpdateResultInterface::class, + [], + '', + false, + true, + true, + [] + ); + + $this->validationResult->expects($this->any())->method('getFailedItems')->willReturn([$priceUpdateResult]); + $this->assertEquals( + [$priceUpdateResult], + $this->model->update([$this->basePriceInterface]) + ); + } + + /** + * Test update method with negative price. + * + * @return void + */ + public function testUpdateWithNegativePrice() + { + $sku = 'sku_1'; + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->validationResult->expects($this->once())->method('getFailedRowIds')->willReturn([0 => 0]); + $this->basePriceInterface->expects($this->exactly(3))->method('getSku')->willReturn($sku); + $this->basePriceInterface->expects($this->exactly(3))->method('getPrice')->willReturn(-15); + $priceUpdateResult = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\PriceUpdateResultInterface::class, + [], + '', + false, + true, + true, + [] + ); + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'price']) + ->willReturn($this->pricePersistence); + $this->validationResult->expects($this->any())->method('getFailedItems')->willReturn([$priceUpdateResult]); + $this->assertEquals( + [$priceUpdateResult], + $this->model->update([$this->basePriceInterface]) + ); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/CostStorageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/CostStorageTest.php new file mode 100644 index 0000000000000..a7c82b553365d --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/CostStorageTest.php @@ -0,0 +1,297 @@ +pricePersistenceFactory = $this->getMock( + \Magento\Catalog\Model\Product\Price\PricePersistenceFactory::class, + ['create'], + [], + '', + false + ); + $this->pricePersistence = $this->getMock( + \Magento\Catalog\Model\Product\Price\PricePersistence::class, + ['get', 'retrieveSkuById', 'update', 'delete', 'getEntityLinkField'], + [], + '', + false + ); + $this->costInterfaceFactory = $this->getMock( + \Magento\Catalog\Api\Data\CostInterfaceFactory::class, + ['create'], + [], + '', + false + ); + $this->costInterface = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\CostInterface::class, + [], + '', + false, + true, + true, + ['setSku', 'setCost', 'setStoreId', 'getSku', 'getCost', 'getStoreId'] + ); + $this->productIdLocator = $this->getMockForAbstractClass( + \Magento\Catalog\Model\ProductIdLocatorInterface::class, + [], + '', + false, + true, + true, + ['retrieveProductIdsBySkus'] + ); + $this->storeRepository = $this->getMockForAbstractClass( + \Magento\Store\Api\StoreRepositoryInterface::class, + [], + '', + false, + true, + true, + ['getById'] + ); + $this->validationResult = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\Validation\Result::class) + ->disableOriginalConstructor() + ->getMock(); + $this->invalidSkuChecker = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\InvalidSkuChecker::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManager->getObject( + \Magento\Catalog\Model\Product\Price\CostStorage::class, + [ + 'pricePersistenceFactory' => $this->pricePersistenceFactory, + 'costInterfaceFactory' => $this->costInterfaceFactory, + 'productIdLocator' => $this->productIdLocator, + 'storeRepository' => $this->storeRepository, + 'validationResult' => $this->validationResult, + 'invalidSkuChecker' => $this->invalidSkuChecker, + 'allowedProductTypes' => ['simple', 'virtual', 'downloadable'], + ] + ); + } + + /** + * Test get method. + * + * @return void + */ + public function testGet() + { + $skus = ['sku_1', 'sku_2']; + $rawPrices = [ + [ + 'row_id' => 1, + 'value' => 15, + 'store_id' => 1 + ], + [ + 'row_id' => 2, + 'value' => 35, + 'store_id' => 1 + ] + ]; + $this->invalidSkuChecker + ->expects($this->atLeastOnce()) + ->method('isSkuListValid'); + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'cost']) + ->willReturn($this->pricePersistence); + $this->pricePersistence->expects($this->once())->method('get')->with($skus)->willReturn($rawPrices); + $this->costInterfaceFactory + ->expects($this->exactly(2)) + ->method('create') + ->willReturn($this->costInterface); + $this->pricePersistence + ->expects($this->exactly(2)) + ->method('retrieveSkuById') + ->willReturnOnConsecutiveCalls('sku_1', 'sku_2'); + $this->pricePersistence->expects($this->atLeastOnce())->method('getEntityLinkField')->willReturn('row_id'); + $this->costInterface + ->expects($this->exactly(2)) + ->method('setSku') + ->withConsecutive(['sku_1'], ['sku_2']) + ->willReturnSelf(); + $this->costInterface + ->expects($this->exactly(2)) + ->method('setCost') + ->withConsecutive([15], [35]) + ->willReturnSelf(); + $this->costInterface + ->expects($this->exactly(2)) + ->method('setStoreId') + ->withConsecutive([1], [1]) + ->willReturnSelf(); + $this->model->get($skus); + } + + /** + * Test update method. + * + * @return void + */ + public function testUpdate() + { + $store = $this->getMockForAbstractClass( + \Magento\Store\Api\Data\StoreInterface::class, + [], + '', + false + ); + $sku = 'sku_1'; + $idsBySku = [ + 'sku_1' => + [ + 1 => \Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL + ] + ]; + $this->costInterface->expects($this->exactly(5))->method('getSku')->willReturn($sku); + $this->productIdLocator + ->expects($this->exactly(1)) + ->method('retrieveProductIdsBySkus')->with([$sku]) + ->willReturn($idsBySku); + $this->costInterface->expects($this->exactly(3))->method('getCost')->willReturn(15); + $this->invalidSkuChecker + ->expects($this->exactly(1)) + ->method('retrieveInvalidSkuList') + ->willReturn([]); + $this->costInterface->expects($this->exactly(2))->method('getStoreId')->willReturn(1); + $this->pricePersistence->expects($this->atLeastOnce())->method('getEntityLinkField')->willReturn('row_id'); + $this->storeRepository->expects($this->once())->method('getById')->with(1)->willReturn($store); + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'cost']) + ->willReturn($this->pricePersistence); + $this->validationResult + ->expects($this->exactly(1)) + ->method('getFailedRowIds') + ->willReturn([]); + $formattedPrices = [ + [ + 'store_id' => 1, + 'row_id' => 1, + 'value' => 15 + ] + ]; + $this->pricePersistence->expects($this->once())->method('update')->with($formattedPrices); + $this->validationResult + ->expects($this->exactly(1)) + ->method('getFailedItems') + ->willReturn([]); + $this->assertEmpty($this->model->update([$this->costInterface])); + } + + /** + * Test update method with negative cost. + */ + public function testUpdateWithNegativeCost() + { + $sku = 'sku_1'; + $this->costInterface->expects($this->exactly(5))->method('getSku')->willReturn($sku); + $this->invalidSkuChecker + ->expects($this->exactly(1)) + ->method('retrieveInvalidSkuList') + ->willReturn([]); + $this->validationResult + ->expects($this->exactly(1)) + ->method('getFailedRowIds') + ->willReturn([0]); + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'cost']) + ->willReturn($this->pricePersistence); + $this->pricePersistence->expects($this->atLeastOnce())->method('update'); + $this->costInterface->expects($this->exactly(4))->method('getCost')->willReturn(-15); + $this->validationResult + ->expects($this->atLeastOnce()) + ->method('getFailedItems'); + $this->model->update([$this->costInterface]); + } + + /** + * Test delete method. + * + * @return void + */ + public function testDelete() + { + $skus = ['sku_1', 'sku_2']; + $this->pricePersistenceFactory + ->expects($this->once()) + ->method('create') + ->with(['attributeCode' => 'cost']) + ->willReturn($this->pricePersistence); + $this->pricePersistence->expects($this->once())->method('delete')->with($skus); + $this->invalidSkuChecker + ->expects($this->exactly(1)) + ->method('isSkuListValid') + ->willReturn(true); + $this->model->delete($skus); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/InvalidSkuCheckerTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/InvalidSkuCheckerTest.php new file mode 100644 index 0000000000000..da0510efb982f --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/InvalidSkuCheckerTest.php @@ -0,0 +1,121 @@ +productIdLocator = $this->getMockBuilder(\Magento\Catalog\Model\ProductIdLocatorInterface::class) + ->setMethods(['retrieveProductIdsBySkus']) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->productRepository = $this->getMockBuilder(\Magento\Catalog\Api\ProductRepositoryInterface::class) + ->setMethods(['get']) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->invalidSkuChecker = $this->objectManagerHelper->getObject( + \Magento\Catalog\Model\Product\Price\InvalidSkuChecker::class, + [ + 'productIdLocator' => $this->productIdLocator, + 'productRepository' => $this->productRepository + ] + ); + } + + /** + * Prepare retrieveInvalidSkuList(). + * + * @param string $productType + * @param string $productSku + * @return void + */ + private function prepareRetrieveInvalidSkuListMethod($productType, $productSku) + { + $idsBySku = [$productSku => [235235235 => $productType]]; + $this->productIdLocator->expects($this->atLeastOnce())->method('retrieveProductIdsBySkus') + ->willReturn($idsBySku); + + $product = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->setMethods(['getPriceType']) + ->disableOriginalConstructor()->getMockForAbstractClass(); + $productPriceType = 0; + $product->expects($this->atLeastOnce())->method('getPriceType')->willReturn($productPriceType); + + $this->productRepository->expects($this->atLeastOnce())->method('get')->willReturn($product); + } + + /** + * Test for retrieveInvalidSkuList(). + * + * @return void + */ + public function testRetrieveInvalidSkuList() + { + $productSku = 'LKJKJ2233636'; + $productType = \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE; + $methodParamSku = 'SDFSDF3242355'; + $skus = [$methodParamSku]; + $allowedProductTypes = [$productType]; + $allowedPriceTypeValue = true; + + $this->prepareRetrieveInvalidSkuListMethod($productType, $productSku); + + $expects = [$methodParamSku, $productSku]; + $result = $this->invalidSkuChecker->retrieveInvalidSkuList($skus, $allowedProductTypes, $allowedPriceTypeValue); + $this->assertEquals($expects, $result); + } + + /** + * Test for isSkuListValid() with Exception. + * + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + * @return void + */ + public function testIsSkuListValidWithException() + { + $productSku = 'LKJKJ2233636'; + $productType = \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE; + $methodParamSku = 'SDFSDF3242355'; + $skus = [$methodParamSku]; + $allowedProductTypes = [$productType]; + $allowedPriceTypeValue = true; + + $this->prepareRetrieveInvalidSkuListMethod($productType, $productSku); + + $this->invalidSkuChecker->isSkuListValid($skus, $allowedProductTypes, $allowedPriceTypeValue); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/PricePersistenceTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/PricePersistenceTest.php new file mode 100644 index 0000000000000..b1a08900b58b9 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/PricePersistenceTest.php @@ -0,0 +1,402 @@ +attributeResource = $this->getMock( + \Magento\Catalog\Model\ResourceModel\Attribute::class, + ['getConnection', 'getTable'], + [], + '', + false + ); + $this->attributeRepository = $this->getMockForAbstractClass( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class, + [], + '', + false, + true, + true, + ['get'] + ); + $this->productIdLocator = $this->getMockForAbstractClass( + \Magento\Catalog\Model\ProductIdLocatorInterface::class, + [], + '', + false, + true, + true, + ['retrieveProductIdsBySkus'] + ); + $this->metadataPool = $this->getMock( + \Magento\Framework\EntityManager\MetadataPool::class, + ['getLinkField', 'getMetadata'], + [], + '', + false + ); + $this->connection = $this->getMockForAbstractClass( + \Magento\Framework\DB\Adapter\AdapterInterface::class, + [], + '', + false, + true, + true, + ['select', 'fetchAll', 'beginTransaction', 'insertOnDuplicate', 'commit', 'rollBack', 'delete'] + ); + $this->productAttribute = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\ProductAttributeInterface::class, + [], + '', + false, + true, + true, + ['getAttributeId'] + ); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManager->getObject( + \Magento\Catalog\Model\Product\Price\PricePersistence::class, + [ + 'attributeResource' => $this->attributeResource, + 'attributeRepository' => $this->attributeRepository, + 'productIdLocator' => $this->productIdLocator, + 'metadataPool' => $this->metadataPool, + ] + ); + } + + /** + * Test get method. + * + * @return void + */ + public function testGet() + { + $attributeId = 5; + $skus = ['sku_1', 'sku_2']; + $idsBySku = [ + 'sku_1' => + [ + 1 => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE + ], + 'sku_2' => + [ + 2 => \Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL + ] + ]; + $select = $this->getMock( + \Magento\Framework\DB\Select::class, + ['from', 'where'], + [], + '', + false + ); + $this->productIdLocator + ->expects($this->once()) + ->method('retrieveProductIdsBySkus')->with($skus) + ->willReturn($idsBySku); + $this->attributeResource->expects($this->exactly(2))->method('getConnection')->willReturn($this->connection); + $this->connection->expects($this->once())->method('select')->willReturn($select); + $this->attributeResource + ->expects($this->once()) + ->method('getTable') + ->with('catalog_product_entity_decimal') + ->willReturn('catalog_product_entity_decimal'); + $select->expects($this->once())->method('from')->with('catalog_product_entity_decimal')->willReturnSelf(); + $this->attributeRepository->expects($this->once())->method('get')->willReturn($this->productAttribute); + $this->productAttribute->expects($this->once())->method('getAttributeId')->willReturn($attributeId); + $select + ->expects($this->exactly(2)) + ->method('where') + ->withConsecutive(['row_id IN (?)', [1, 2]], ['attribute_id = ?', $attributeId]) + ->willReturnSelf(); + $this->metadataPool->expects($this->atLeastOnce())->method('getMetadata')->willReturnSelf(); + $this->metadataPool->expects($this->atLeastOnce())->method('getLinkField')->willReturn('row_id'); + $this->model->get($skus); + } + + /** + * Test update method. + * + * @return void + */ + public function testUpdate() + { + $attributeId = 5; + $prices = [ + [ + 'store_id' => 1, + 'row_id' => 1, + 'value' => 15 + ] + ]; + $this->attributeRepository->expects($this->once())->method('get')->willReturn($this->productAttribute); + $this->productAttribute->expects($this->once())->method('getAttributeId')->willReturn($attributeId); + $this->attributeResource->expects($this->exactly(2))->method('getConnection')->willReturn($this->connection); + $this->connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $this->attributeResource + ->expects($this->once()) + ->method('getTable') + ->with('catalog_product_entity_decimal') + ->willReturn('catalog_product_entity_decimal'); + $this->connection + ->expects($this->once()) + ->method('insertOnDuplicate') + ->with( + 'catalog_product_entity_decimal', + [ + [ + 'store_id' => 1, + 'row_id' => 1, + 'value' => 15, + 'attribute_id' => 5, + ] + ], + ['value'] + ) + ->willReturnSelf(); + $this->connection->expects($this->once())->method('commit')->willReturnSelf(); + $this->model->update($prices); + } + + /** + * Test update method throws exception. + * + * @expectedException \Magento\Framework\Exception\CouldNotSaveException + * @expectedExceptionMessage Could not save Prices. + */ + public function testUpdateWithException() + { + $attributeId = 5; + $prices = [ + [ + 'store_id' => 1, + 'row_id' => 1, + 'value' => 15 + ] + ]; + $this->attributeRepository->expects($this->once())->method('get')->willReturn($this->productAttribute); + $this->productAttribute->expects($this->once())->method('getAttributeId')->willReturn($attributeId); + $this->attributeResource->expects($this->exactly(2))->method('getConnection')->willReturn($this->connection); + $this->connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $this->attributeResource + ->expects($this->once()) + ->method('getTable') + ->with('catalog_product_entity_decimal') + ->willReturn('catalog_product_entity_decimal'); + $this->connection + ->expects($this->once()) + ->method('insertOnDuplicate') + ->with( + 'catalog_product_entity_decimal', + [ + [ + 'store_id' => 1, + 'row_id' => 1, + 'value' => 15, + 'attribute_id' => 5, + ] + ], + ['value'] + ) + ->willReturnSelf(); + $this->connection->expects($this->once())->method('commit')->willThrowException(new \Exception()); + $this->connection->expects($this->once())->method('rollback')->willReturnSelf(); + $this->model->update($prices); + } + + /** + * Test delete method. + * + * @return void + */ + public function testDelete() + { + $attributeId = 5; + $skus = ['sku_1', 'sku_2']; + $idsBySku = [ + 'sku_1' => + [ + 1 => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE + ], + 'sku_2' => + [ + 2 => \Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL + ] + ]; + $this->productIdLocator + ->expects($this->once()) + ->method('retrieveProductIdsBySkus')->with($skus) + ->willReturn($idsBySku); + $this->attributeRepository->expects($this->once())->method('get')->willReturn($this->productAttribute); + $this->productAttribute->expects($this->once())->method('getAttributeId')->willReturn($attributeId); + $this->attributeResource->expects($this->exactly(2))->method('getConnection')->willReturn($this->connection); + $this->connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $this->attributeResource + ->expects($this->once()) + ->method('getTable') + ->with('catalog_product_entity_decimal') + ->willReturn('catalog_product_entity_decimal'); + $this->connection + ->expects($this->once()) + ->method('delete') + ->with( + 'catalog_product_entity_decimal', + [ + 'attribute_id = ?' => $attributeId, + 'row_id IN (?)' => [1, 2] + ] + ) + ->willReturnSelf(); + $this->connection->expects($this->once())->method('commit')->willReturnSelf(); + $this->metadataPool->expects($this->atLeastOnce())->method('getMetadata')->willReturnSelf(); + $this->metadataPool->expects($this->atLeastOnce())->method('getLinkField')->willReturn('row_id'); + $this->model->delete($skus); + } + + /** + * Test delete method throws exception. + * + * @expectedException \Magento\Framework\Exception\CouldNotDeleteException + * @expectedExceptionMessage Could not delete Prices + */ + public function testDeleteWithException() + { + $attributeId = 5; + $skus = ['sku_1', 'sku_2']; + $idsBySku = [ + 'sku_1' => + [ + 1 => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE + ], + 'sku_2' => + [ + 2 => \Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL + ] + ]; + $this->productIdLocator + ->expects($this->once()) + ->method('retrieveProductIdsBySkus')->with($skus) + ->willReturn($idsBySku); + $this->attributeRepository->expects($this->once())->method('get')->willReturn($this->productAttribute); + $this->productAttribute->expects($this->once())->method('getAttributeId')->willReturn($attributeId); + $this->attributeResource->expects($this->exactly(2))->method('getConnection')->willReturn($this->connection); + $this->connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $this->attributeResource + ->expects($this->once()) + ->method('getTable') + ->with('catalog_product_entity_decimal') + ->willReturn('catalog_product_entity_decimal'); + $this->connection + ->expects($this->once()) + ->method('delete') + ->with( + 'catalog_product_entity_decimal', + [ + 'attribute_id = ?' => $attributeId, + 'row_id IN (?)' => [1, 2] + ] + ) + ->willReturnSelf(); + $this->connection->expects($this->once())->method('commit')->willThrowException(new \Exception()); + $this->connection->expects($this->once())->method('rollBack')->willReturnSelf(); + $this->metadataPool->expects($this->atLeastOnce())->method('getMetadata')->willReturnSelf(); + $this->metadataPool->expects($this->atLeastOnce())->method('getLinkField')->willReturn('row_id'); + $this->model->delete($skus); + } + + /** + * Test retrieveSkuById method. + * + * @param int|null $expectedResult + * @param int $id + * @param array $skus + * @dataProvider dataProviderRetrieveSkuById + */ + public function testRetrieveSkuById($expectedResult, $id, array $skus) + { + $this->productIdLocator + ->expects($this->once()) + ->method('retrieveProductIdsBySkus') + ->willReturn($skus); + + $this->assertEquals($expectedResult, $this->model->retrieveSkuById($id, $skus)); + } + + /** + * Data provider for retrieveSkuById method. + * + * @return array + */ + public function dataProviderRetrieveSkuById() + { + return [ + [ + null, + 2, + ['sku_1' => [1 => 1]] + ], + [ + 'sku_1', + 1, + ['sku_1' => [1 => 1]] + ], + [ + null, + 1, + ['sku_1' => [2 => 1]] + ], + ]; + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/SpecialPriceStorageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/SpecialPriceStorageTest.php new file mode 100644 index 0000000000000..380d6bacbf635 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/SpecialPriceStorageTest.php @@ -0,0 +1,294 @@ +specialPriceResource = $this->getMockBuilder(\Magento\Catalog\Api\SpecialPriceInterface::class) + ->disableOriginalConstructor()->setMethods(['get', 'update', 'delete', 'getEntityLinkField'])->getMock(); + $this->productIdLocator = $this->getMockBuilder(\Magento\Catalog\Model\ProductIdLocatorInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->storeRepository = $this->getMockBuilder(\Magento\Store\Api\StoreRepositoryInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->invalidSkuChecker = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\InvalidSkuChecker::class) + ->disableOriginalConstructor()->getMock(); + $this->validationResult = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\Validation\Result::class) + ->disableOriginalConstructor()->getMock(); + $this->specialPriceFactory = $this->getMockBuilder( + \Magento\Catalog\Api\Data\SpecialPriceInterfaceFactory::class + )->disableOriginalConstructor()->setMethods(['create'])->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManager->getObject( + \Magento\Catalog\Model\Product\Price\SpecialPriceStorage::class, + [ + 'specialPriceResource' => $this->specialPriceResource, + 'specialPriceFactory' => $this->specialPriceFactory, + 'productIdLocator' => $this->productIdLocator, + 'storeRepository' => $this->storeRepository, + 'invalidSkuChecker' => $this->invalidSkuChecker, + 'validationResult' => $this->validationResult, + ] + ); + } + + /** + * Test get method. + * + * @return void + */ + public function testGet() + { + $skus = ['sku_1', 'sku_2']; + $rawPrices = [ + [ + 'entity_id' => 1, + 'value' => 15, + 'store_id' => 1, + 'sku' => 'sku_1', + 'price_from' => '2016-12-20 01:02:03', + 'price_to' => '2016-12-21 01:02:03', + ], + [ + 'entity_id' => 2, + 'value' => 15, + 'store_id' => 1, + 'price_from' => '2016-12-20 01:02:03', + 'price_to' => '2016-12-21 01:02:03', + ], + [ + 'entity_id' => 3, + 'value' => 15, + 'store_id' => 1, + 'price_from' => '2016-12-20 01:02:03', + 'price_to' => '2016-12-21 01:02:03', + ], + ]; + $this->specialPriceResource->expects($this->once())->method('get')->willReturn($rawPrices); + $this->specialPriceResource->expects($this->atLeastOnce()) + ->method('getEntityLinkField')->willReturn('entity_id'); + + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\SpecialPriceInterface::class) + ->disableOriginalConstructor()->getMock(); + $price->expects($this->exactly(3))->method('setPrice'); + $this->specialPriceFactory->expects($this->atLeastOnce())->method('create')->willReturn($price); + $this->productIdLocator->expects($this->atLeastOnce())->method('retrieveProductIdsBySkus')->willReturn( + [ + 'sku_2' => [2 => 'prod'] + ] + ); + $this->model->get($skus); + } + + /** + * Test update method. + * + * @return void + */ + public function testUpdate() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\SpecialPriceInterface::class) + ->disableOriginalConstructor()->getMock(); + + $prices = [1 => $price]; + $price->expects($this->atLeastOnce())->method('getSku')->willReturn('sku_1'); + $price->expects($this->atLeastOnce())->method('getPrice')->willReturn(15); + $price->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); + $price->expects($this->atLeastOnce())->method('getPriceFrom')->willReturn('2016-12-20 01:02:03'); + $price->expects($this->atLeastOnce())->method('getPriceTo')->willReturn('2016-12-21 01:02:03'); + + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->storeRepository->expects($this->once())->method('getById'); + $this->validationResult->expects($this->never())->method('addFailedItem'); + $this->validationResult->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([]); + + $this->specialPriceResource->expects($this->once())->method('update')->with($prices); + + $this->model->update($prices); + } + + /** + * Test update method with invalid sku. + * + * @return void + */ + public function testUpdateWithInvalidSku() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\SpecialPriceInterface::class) + ->disableOriginalConstructor()->getMock(); + $prices = [1 => $price]; + + $price->expects($this->atLeastOnce())->method('getSku')->willReturn('sku_1'); + $price->expects($this->atLeastOnce())->method('getPrice')->willReturn(15); + $price->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); + $price->expects($this->atLeastOnce())->method('getPriceFrom')->willReturn('2016-12-20 01:02:03'); + $price->expects($this->atLeastOnce())->method('getPriceTo')->willReturn('2016-12-21 01:02:03'); + + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn(['sku_1']); + $this->storeRepository->expects($this->once())->method('getById'); + $this->validationResult->expects($this->once())->method('addFailedItem')->with(1); + $this->validationResult->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([1]); + + $this->specialPriceResource->expects($this->once())->method('update')->with([]); + + $this->model->update($prices); + } + + /** + * Test update method with price = null. + * + * @return void + */ + public function testUpdateWithoutPrice() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\SpecialPriceInterface::class) + ->disableOriginalConstructor()->getMock(); + $prices = [1 => $price]; + + $price->expects($this->atLeastOnce())->method('getSku')->willReturn('sku_1'); + $price->expects($this->atLeastOnce())->method('getPrice')->willReturn(null); + $price->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); + $price->expects($this->atLeastOnce())->method('getPriceFrom')->willReturn('2016-12-20 01:02:03'); + $price->expects($this->atLeastOnce())->method('getPriceTo')->willReturn('2016-12-21 01:02:03'); + + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->storeRepository->expects($this->once())->method('getById'); + $this->validationResult->expects($this->once())->method('addFailedItem')->with(1); + $this->validationResult->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([1]); + + $this->specialPriceResource->expects($this->once())->method('update')->with([]); + + $this->model->update($prices); + } + + /** + * Test update method with price = null. + * + * @return void + */ + public function testUpdateWithException() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\SpecialPriceInterface::class) + ->disableOriginalConstructor()->getMock(); + $prices = [1 => $price]; + + $price->expects($this->atLeastOnce())->method('getSku')->willReturn('sku_1'); + $price->expects($this->atLeastOnce())->method('getPrice')->willReturn(15); + $price->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); + $price->expects($this->atLeastOnce())->method('getPriceFrom')->willReturn('2016-12-20 01:02:03'); + $price->expects($this->atLeastOnce())->method('getPriceTo')->willReturn('2016-12-21 01:02:03'); + + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->storeRepository->expects($this->once())->method('getById') + ->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException()); + $this->validationResult->expects($this->once())->method('addFailedItem')->with(1); + $this->validationResult->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([1]); + + $this->specialPriceResource->expects($this->once())->method('update')->with([]); + + $this->model->update($prices); + } + + /** + * Test update method with incorrect price_from field. + * + * @return void + */ + public function testUpdateWithIncorrectPriceFrom() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\SpecialPriceInterface::class) + ->disableOriginalConstructor()->getMock(); + $prices = [1 => $price]; + + $price->expects($this->atLeastOnce())->method('getSku')->willReturn('sku_1'); + $price->expects($this->atLeastOnce())->method('getPrice')->willReturn(15); + $price->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); + $price->expects($this->atLeastOnce())->method('getPriceFrom')->willReturn('incorrect'); + $price->expects($this->atLeastOnce())->method('getPriceTo')->willReturn('2016-12-21 01:02:03'); + + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->storeRepository->expects($this->once())->method('getById'); + $this->validationResult->expects($this->once())->method('addFailedItem')->with(1); + $this->validationResult->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([1]); + + $this->specialPriceResource->expects($this->once())->method('update')->with([]); + + $this->model->update($prices); + } + + /** + * Test update method with incorrect price_to field. + * + * @return void + */ + public function testUpdateWithIncorrectPriceTo() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\SpecialPriceInterface::class) + ->disableOriginalConstructor()->getMock(); + $prices = [1 => $price]; + + $price->expects($this->atLeastOnce())->method('getSku')->willReturn('sku_1'); + $price->expects($this->atLeastOnce())->method('getPrice')->willReturn(15); + $price->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1); + $price->expects($this->atLeastOnce())->method('getPriceFrom')->willReturn('2016-12-21 01:02:03'); + $price->expects($this->atLeastOnce())->method('getPriceTo')->willReturn('incorrect'); + + $this->invalidSkuChecker->expects($this->once())->method('retrieveInvalidSkuList')->willReturn([]); + $this->storeRepository->expects($this->once())->method('getById'); + $this->validationResult->expects($this->once())->method('addFailedItem')->with(1); + $this->validationResult->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([1]); + + $this->specialPriceResource->expects($this->once())->method('update')->with([]); + + $this->model->update($prices); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/TierPriceStorageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/TierPriceStorageTest.php new file mode 100644 index 0000000000000..398b340da08cd --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/TierPriceStorageTest.php @@ -0,0 +1,323 @@ +tierPricePersistence = $this->getMock( + \Magento\Catalog\Model\Product\Price\TierPricePersistence::class, + [], + [], + '', + false + ); + $this->tierPricePersistence->expects($this->any()) + ->method('getEntityLinkField') + ->willReturn('row_id'); + $this->tierPriceValidator = $this->getMock( + \Magento\Catalog\Model\Product\Price\Validation\TierPriceValidator::class, + [], + [], + '', + false + ); + $this->tierPriceFactory = $this->getMock( + \Magento\Catalog\Model\Product\Price\TierPriceFactory::class, + [], + [], + '', + false + ); + $this->priceIndexer = $this->getMock( + \Magento\Catalog\Model\Indexer\Product\Price::class, + [], + [], + '', + false + ); + $this->productIdLocator = $this->getMock( + \Magento\Catalog\Model\ProductIdLocatorInterface::class, + [], + [], + '', + false + ); + $this->config = $this->getMock( + \Magento\PageCache\Model\Config::class, + [], + [], + '', + false + ); + $this->typeList = $this->getMock( + \Magento\Framework\App\Cache\TypeListInterface::class, + [], + [], + '', + false + ); + $this->invalidSkuChecker = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\InvalidSkuChecker::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->tierPriceStorage = $objectManager->getObject( + \Magento\Catalog\Model\Product\Price\TierPriceStorage::class, + [ + 'tierPricePersistence' => $this->tierPricePersistence, + 'tierPriceValidator' => $this->tierPriceValidator, + 'tierPriceFactory' => $this->tierPriceFactory, + 'priceIndexer' => $this->priceIndexer, + 'productIdLocator' => $this->productIdLocator, + 'config' => $this->config, + 'invalidSkuChecker' => $this->invalidSkuChecker, + 'typeList' => $this->typeList, + ] + ); + } + + /** + * Test get method. + * @return void + */ + public function testGet() + { + $skus = ['simple', 'virtual']; + $this->productIdLocator->expects($this->atLeastOnce()) + ->method('retrieveProductIdsBySkus') + ->with(['simple', 'virtual']) + ->willReturn(['simple' => ['2' => 'simple'], 'virtual' => ['3' => 'virtual']]); + $this->tierPricePersistence->expects($this->once()) + ->method('get') + ->willReturn( + [ + [ + 'value_id' => 1, + 'row_id' => 2, + 'all_groups' => 1, + 'customer_group_id' => 0, + 'qty' => 2.0000, + 'value' => 2.0000, + 'percentage_value' => null, + 'website_id' => 0 + ], + [ + 'value_id' => 2, + 'row_id' => 3, + 'all_groups' => 1, + 'customer_group_id' => 0, + 'qty' => 3.0000, + 'value' => 3.0000, + 'percentage_value' => null, + 'website_id' => 0 + ] + ] + ); + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\TierPriceInterface::class)->getMockForAbstractClass(); + $this->tierPriceFactory->expects($this->at(0))->method('create')->willReturn($price); + $this->tierPriceFactory->expects($this->at(1))->method('create')->willReturn($price); + $prices = $this->tierPriceStorage->get($skus); + $this->assertNotEmpty($prices); + $this->assertEquals(2, count($prices)); + } + + /** + * Test update method. + * @return void + */ + public function testUpdate() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\TierPriceInterface::class)->getMockForAbstractClass(); + $result = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\Validation\Result::class) + ->disableOriginalConstructor() + ->getMock(); + $result->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([]); + $this->productIdLocator->expects($this->atLeastOnce()) + ->method('retrieveProductIdsBySkus') + ->willReturn(['simple' => ['2' => 'simple'], 'virtual' => ['3' => 'virtual']]); + $this->tierPriceValidator + ->expects($this->atLeastOnce()) + ->method('retrieveValidationResult') + ->willReturn($result); + $this->tierPriceFactory->expects($this->atLeastOnce())->method('createSkeleton')->willReturn( + [ + 'row_id' => 2, + 'all_groups' => 1, + 'customer_group_id' => 0, + 'qty' => 2, + 'value' => 3, + 'percentage_value' => null, + 'website_id' => 0 + ] + ); + $this->tierPricePersistence->expects($this->once()) + ->method('get') + ->willReturn( + [ + [ + 'value_id' => 1, + 'row_id' => 2, + 'all_groups' => 1, + 'customer_group_id' => 0, + 'qty' => 2.0000, + 'value' => 2.0000, + 'percentage_value' => null, + 'website_id' => 0 + ] + ] + ); + $this->tierPricePersistence->expects($this->atLeastOnce())->method('update'); + $this->priceIndexer->expects($this->atLeastOnce())->method('execute'); + $this->config->expects($this->atLeastOnce())->method('isEnabled')->willReturn(true); + $this->typeList->expects($this->atLeastOnce())->method('invalidate'); + $price->method('getSku')->willReturn('simple'); + $this->assertEmpty($this->tierPriceStorage->update([$price])); + } + + /** + * Test replace method. + * @return void + */ + public function testReplace() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\TierPriceInterface::class)->getMockForAbstractClass(); + $price->method('getSku')->willReturn('virtual'); + $result = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\Validation\Result::class) + ->disableOriginalConstructor() + ->getMock(); + $result->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([]); + $this->productIdLocator->expects($this->atLeastOnce()) + ->method('retrieveProductIdsBySkus') + ->willReturn(['simple' => ['2' => 'simple'], 'virtual' => ['3' => 'virtual']]); + + $this->tierPriceValidator + ->expects($this->atLeastOnce()) + ->method('retrieveValidationResult') + ->willReturn($result); + $this->tierPriceFactory->expects($this->atLeastOnce())->method('createSkeleton')->willReturn( + [ + 'row_id' => 3, + 'all_groups' => 1, + 'customer_group_id' => 0, + 'qty' => 3, + 'value' => 7, + 'percentage_value' => null, + 'website_id' => 0 + ] + ); + $this->tierPricePersistence->expects($this->atLeastOnce())->method('replace'); + $this->priceIndexer->expects($this->atLeastOnce())->method('execute'); + $this->config->expects($this->atLeastOnce())->method('isEnabled')->willReturn(true); + $this->typeList->expects($this->atLeastOnce())->method('invalidate'); + $this->assertEmpty($this->tierPriceStorage->replace([$price])); + } + + /** + * Test delete method. + * @return void + */ + public function testDelete() + { + $price = $this->getMockBuilder(\Magento\Catalog\Api\Data\TierPriceInterface::class)->getMockForAbstractClass(); + $price->method('getSku')->willReturn('simple'); + $result = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\Validation\Result::class) + ->disableOriginalConstructor() + ->getMock(); + $result->expects($this->atLeastOnce())->method('getFailedRowIds')->willReturn([]); + $this->tierPriceValidator->expects($this->atLeastOnce()) + ->method('retrieveValidationResult') + ->willReturn($result); + $this->productIdLocator->expects($this->atLeastOnce()) + ->method('retrieveProductIdsBySkus') + ->willReturn(['simple' => ['2' => 'simple']]); + $this->tierPricePersistence->expects($this->once()) + ->method('get') + ->willReturn( + [ + [ + 'value_id' => 7, + 'row_id' => 7, + 'all_groups' => 1, + 'customer_group_id' => 0, + 'qty' => 5.0000, + 'value' => 6.0000, + 'percentage_value' => null, + 'website_id' => 0 + ] + ] + ); + $this->tierPriceFactory->expects($this->atLeastOnce())->method('createSkeleton')->willReturn( + [ + 'row_id' => 3, + 'all_groups' => 1, + 'customer_group_id' => 0, + 'qty' => 3, + 'value' => 7, + 'percentage_value' => null, + 'website_id' => 0 + ] + ); + $this->tierPricePersistence->expects($this->atLeastOnce())->method('delete'); + $this->priceIndexer->expects($this->atLeastOnce())->method('execute'); + $this->config->expects($this->atLeastOnce())->method('isEnabled')->willReturn(true); + $this->typeList->expects($this->atLeastOnce())->method('invalidate'); + $this->assertEmpty($this->tierPriceStorage->delete([$price])); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/Validation/TierPriceValidatorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/Validation/TierPriceValidatorTest.php new file mode 100644 index 0000000000000..0505d7c1b8175 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Price/Validation/TierPriceValidatorTest.php @@ -0,0 +1,300 @@ +productIdLocator = $this->getMockBuilder(\Magento\Catalog\Model\ProductIdLocatorInterface::class) + ->setMethods(['retrieveProductIdsBySkus']) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->searchCriteriaBuilder = $this->getMockBuilder(\Magento\Framework\Api\SearchCriteriaBuilder::class) + ->setMethods(['addFilters', 'create']) + ->disableOriginalConstructor()->getMock(); + + $this->filterBuilder = $this->getMockBuilder(\Magento\Framework\Api\FilterBuilder::class) + ->setMethods(['setField', 'setValue', 'create']) + ->disableOriginalConstructor()->getMock(); + + $this->customerGroupRepository = $this->getMockBuilder(\Magento\Customer\Api\GroupRepositoryInterface::class) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->websiteRepository = $this->getMockBuilder(\Magento\Store\Api\WebsiteRepositoryInterface::class) + ->setMethods(['getById']) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->tierPricePersistence = $this + ->getMockBuilder(\Magento\Catalog\Model\Product\Price\TierPricePersistence::class) + ->disableOriginalConstructor()->getMock(); + + $this->validationResult = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\Validation\Result::class) + ->setMethods(['addFailedItem']) + ->disableOriginalConstructor()->getMock(); + + $this->invalidSkuChecker = $this->getMockBuilder(\Magento\Catalog\Model\Product\Price\InvalidSkuChecker::class) + ->setMethods(['isSkuListValid', 'retrieveInvalidSkuList']) + ->disableOriginalConstructor()->getMock(); + + $this->tierPrice = $this->getMockBuilder(\Magento\Catalog\Api\Data\TierPriceInterface::class) + ->setMethods(['getSku', 'getPrice', 'getPriceType', 'getQuantity', 'getWebsiteId']) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->tierPriceValidator = $this->objectManagerHelper->getObject( + \Magento\Catalog\Model\Product\Price\Validation\TierPriceValidator::class, + [ + 'productIdLocator' => $this->productIdLocator, + 'searchCriteriaBuilder' => $this->searchCriteriaBuilder, + 'filterBuilder' => $this->filterBuilder, + 'customerGroupRepository' => $this->customerGroupRepository, + 'websiteRepository' => $this->websiteRepository, + 'tierPricePersistence' => $this->tierPricePersistence, + 'validationResult' => $this->validationResult, + 'invalidSkuChecker' => $this->invalidSkuChecker + ] + ); + } + + /** + * Prepare CustomerGroupRepository mock. + * + * @param array $returned + * @return void + */ + private function prepareCustomerGroupRepositoryMock(array $returned) + { + $searchCriteria = $this + ->getMockBuilder(\Magento\Framework\Api\Search\SearchCriteriaInterface::class) + ->disableOriginalConstructor()->getMock(); + + $filter = $this->getMockBuilder(\Magento\Framework\Api\AbstractSimpleObject::class) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $this->filterBuilder->expects($this->atLeastOnce())->method('setField')->willReturnSelf(); + $this->filterBuilder->expects($this->atLeastOnce())->method('setValue')->willReturnSelf(); + $this->filterBuilder->expects($this->atLeastOnce())->method('create')->willReturn($filter); + + $this->searchCriteriaBuilder->expects($this->atLeastOnce())->method('addFilters')->willReturnSelf(); + $this->searchCriteriaBuilder->expects($this->atLeastOnce())->method('create')->willReturn($searchCriteria); + + $customerGroupSearchResults = $this + ->getMockBuilder(\Magento\Customer\Api\Data\GroupSearchResultsInterface::class) + ->disableOriginalConstructor()->getMock(); + $customerGroupSearchResults->expects($this->once())->method('getItems') + ->willReturn($returned['customerGroupSearchResults_getItems']); + + $this->customerGroupRepository->expects($this->atLeastOnce())->method('getList') + ->willReturn($customerGroupSearchResults); + } + + /** + * Prepare retrieveValidationResult(). + * + * @param string $sku + * @param array $returned + * @return void + */ + private function prepareRetrieveValidationResultMethod($sku, array $returned) + { + $this->tierPrice->expects($this->atLeastOnce())->method('getSku')->willReturn($sku); + $tierPriceValue = 104; + $this->tierPrice->expects($this->atLeastOnce())->method('getPrice')->willReturn($tierPriceValue); + $this->tierPrice->expects($this->atLeastOnce())->method('getPriceType') + ->willReturn($returned['tierPrice_getPriceType']); + $qty = 0; + $this->tierPrice->expects($this->atLeastOnce())->method('getQuantity')->willReturn($qty); + $websiteId = 0; + $invalidWebsiteId = 4; + $this->tierPrice->expects($this->atLeastOnce())->method('getWebsiteId') + ->willReturnOnConsecutiveCalls($websiteId, $websiteId, $websiteId, $invalidWebsiteId, $websiteId); + $this->tierPrice->expects($this->atLeastOnce())->method('getCustomerGroup') + ->willReturn($returned['tierPrice_getCustomerGroup']); + + $skuDiff = [$sku]; + $this->invalidSkuChecker->expects($this->atLeastOnce())->method('retrieveInvalidSkuList')->willReturn($skuDiff); + + $productId = 3346346; + $productType = \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE; + $idsBySku = [ + $sku => [$productId => $productType] + ]; + $this->productIdLocator->expects($this->atLeastOnce())->method('retrieveProductIdsBySkus') + ->willReturn($idsBySku); + } + + /** + * Test for validateSkus(). + * + * @return void + */ + public function testValidateSkus() + { + $skus = ['SDFS234234']; + + $this->invalidSkuChecker->expects($this->atLeastOnce())->method('isSkuListValid'); + + $expected = null; + $this->assertEquals($expected, $this->tierPriceValidator->validateSkus($skus)); + } + + /** + * Test for retrieveValidationResult(). + * + * @param array $returned + * @dataProvider retrieveValidationResultDataProvider + * @return void + */ + public function testRetrieveValidationResult(array $returned) + { + $sku = 'ASDF234234'; + + $prices = [$this->tierPrice]; + $existingPrices = [$this->tierPrice]; + + $this->prepareRetrieveValidationResultMethod($sku, $returned); + + $website = $this->getMockBuilder(\Magento\Store\Api\Data\WebsiteInterface::class) + ->disableOriginalConstructor()->getMockForAbstractClass(); + $this->websiteRepository->expects($this->atLeastOnce())->method('getById')->willReturn($website); + + $this->prepareCustomerGroupRepositoryMock($returned); + + $expects = $this->validationResult; + $this->assertEquals($expects, $this->tierPriceValidator->retrieveValidationResult($prices, $existingPrices)); + } + + /** + * Data provider for retrieveValidationResult() test. + * + * @return array + */ + public function retrieveValidationResultDataProvider() + { + $customerGroupName = 'test_Group'; + + $customerGroup = $this->getMockBuilder(\Magento\Customer\Api\Data\GroupInterface::class) + ->setMethods(['getCode', 'getId']) + ->disableOriginalConstructor()->getMockForAbstractClass(); + + $customerGroup->expects($this->atLeastOnce())->method('getCode')->willReturn($customerGroupName); + $customerGroupId = 23; + $customerGroup->expects($this->atLeastOnce())->method('getId')->willReturn($customerGroupId); + + return [ + [ + [ + 'tierPrice_getCustomerGroup' => $customerGroupName, + 'tierPrice_getPriceType' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT, + 'customerGroupSearchResults_getItems' => [$customerGroup] + ] + ], + [ + [ + 'tierPrice_getCustomerGroup' => $customerGroupName, + 'tierPrice_getPriceType' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_FIXED, + 'customerGroupSearchResults_getItems' => [] + ] + ] + ]; + } + + /** + * Test for retrieveValidationResult() with Exception. + * + * @return void + */ + public function testRetrieveValidationResultWithException() + { + $sku = 'ASDF234234'; + $customerGroupName = 'test_Group'; + + $prices = [$this->tierPrice]; + $existingPrices = [$this->tierPrice]; + + $returned = [ + 'tierPrice_getPriceType' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT, + 'customerGroupSearchResults_getItems' => [], + 'tierPrice_getCustomerGroup' => $customerGroupName, + ]; + + $this->prepareRetrieveValidationResultMethod($sku, $returned); + + $exception = new \Magento\Framework\Exception\NoSuchEntityException(); + + $this->websiteRepository->expects($this->atLeastOnce())->method('getById')->willThrowException($exception); + + $this->prepareCustomerGroupRepositoryMock($returned); + + $expects = $this->validationResult; + $this->assertEquals($expects, $this->tierPriceValidator->retrieveValidationResult($prices, $existingPrices)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/PriceModifier/CompositeTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/PriceModifier/CompositeTest.php index 35aad84447526..7b27d3b07593f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/PriceModifier/CompositeTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/PriceModifier/CompositeTest.php @@ -1,6 +1,6 @@ product = $this->getMock( + \Magento\Catalog\Model\Product::class, + ['__wakeup', 'getCanShowPrice'], + [], + '', + false + ); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->object = $objectManager->getObject( + \Magento\Catalog\Model\Product\Pricing\Renderer\SalableResolver::class + ); + } + + public function testSalableItem() + { + $this->product->expects($this->any()) + ->method('getCanShowPrice') + ->willReturn(true); + + $result = $this->object->isSalable($this->product); + $this->assertTrue($result); + } + + public function testNotSalableItem() + { + $this->product->expects($this->any()) + ->method('getCanShowPrice') + ->willReturn(false); + + $result = $this->object->isSalable($this->product); + $this->assertFalse($result); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/ProductList/ToolbarTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/ProductList/ToolbarTest.php index 7bafd7a5b5686..a7eb5069d02f0 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/ProductList/ToolbarTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/ProductList/ToolbarTest.php @@ -1,6 +1,6 @@ objectManagerHelper = new ObjectManagerHelper($this); $this->product = $this->objectManagerHelper->getObject(\Magento\Catalog\Model\Product::class); - $this->tpFactory = $this->getMockForAbstractClass( + $this->tpFactory = $this->getMock( \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory::class, + ['create'], [], '', false, - true, - true, - ['create'] + false, + false ); $this->websiteMock = $this->getMock(\Magento\Store\Model\Website::class, ['getId'], [], '', false); - $storeMangerMock = $this->getMockForAbstractClass( + $storeMangerMock = $this->getMockForAbstractClass( \Magento\Store\Model\StoreManagerInterface::class, [], '', @@ -84,7 +88,7 @@ protected function setUp() ->method('getWebsite') ->will($this->returnValue($this->websiteMock)); - $this->scopeConfigMock = $this->getMockForAbstractClass( + $this->scopeConfigMock = $this->getMockForAbstractClass( \Magento\Framework\App\Config\ScopeConfigInterface::class, [], '', @@ -94,7 +98,7 @@ protected function setUp() ['getValue'] ); - $group = $this->getMock( + $group = $this->getMock( \Magento\Customer\Model\Data\Group::class, [], [], @@ -107,7 +111,7 @@ protected function setUp() $this->groupManagementMock->expects($this->any())->method('getAllCustomersGroup') ->will($this->returnValue($group)); - $this->model = $this->objectManagerHelper->getObject( + $this->model = $this->objectManagerHelper->getObject( \Magento\Catalog\Model\Product\Type\Price::class, [ 'tierPriceFactory' => $this->tpFactory, @@ -164,12 +168,8 @@ public function pricesDataProvider() public function testTierPrices($priceScope, $expectedWebsiteId) { // establish the behavior of the mocks - $this->scopeConfigMock->expects($this->any()) - ->method('getValue') - ->will($this->returnValue($priceScope)); - $this->websiteMock->expects($this->any()) - ->method('getId') - ->will($this->returnValue($expectedWebsiteId)); + $this->scopeConfigMock->expects($this->any())->method('getValue')->will($this->returnValue($priceScope)); + $this->websiteMock->expects($this->any())->method('getId')->will($this->returnValue($expectedWebsiteId)); $this->tpFactory->expects($this->any()) ->method('create') ->will($this->returnCallback(function () { @@ -177,14 +177,21 @@ public function testTierPrices($priceScope, $expectedWebsiteId) })); // create sample TierPrice objects that would be coming from a REST call + $tierPriceExtensionMock = $this->getMockBuilder(ProductTierPriceExtensionInterface::class) + ->setMethods(['getWebsiteId', 'setWebsiteId', 'getPercentageValue', 'setPercentageValue']) + ->getMock(); + $tierPriceExtensionMock->expects($this->any())->method('getWebsiteId')->willReturn($expectedWebsiteId); + $tierPriceExtensionMock->expects($this->any())->method('getPercentageValue')->willReturn(null); $tp1 = $this->objectManagerHelper->getObject(\Magento\Catalog\Model\Product\TierPrice::class); $tp1->setValue(10); $tp1->setCustomerGroupId(1); $tp1->setQty(11); + $tp1->setExtensionAttributes($tierPriceExtensionMock); $tp2 = $this->objectManagerHelper->getObject(\Magento\Catalog\Model\Product\TierPrice::class); $tp2->setValue(20); $tp2->setCustomerGroupId(2); $tp2->setQty(22); + $tp2->setExtensionAttributes($tierPriceExtensionMock); $tps = [$tp1, $tp2]; // force the product to have null tier prices @@ -213,11 +220,28 @@ public function testTierPrices($priceScope, $expectedWebsiteId) $this->assertEquals($tps[$i]->getQty(), $tpData['price_qty'], 'Qty does not match'); } + $tierPriceExtention = $this->getMockBuilder(ProductTierPriceExtensionInterface::class) + ->setMethods(['getWebsiteId', 'setWebsiteId', 'getPercentageValue', 'setPercentageValue']) + ->getMock(); + $tierPriceExtention->expects($this->any())->method('getPercentageValue')->willReturn(50); + $tierPriceExtention->expects($this->any())->method('setWebsiteId'); + $factoryMock = $this->getMockBuilder(ProductTierPriceExtensionFactory::class)->setMethods(['create']) + ->disableOriginalConstructor()->getMock(); + $factoryMock->expects($this->any())->method('create')->willReturn($tierPriceExtention); + + $reflection = new \ReflectionClass(get_class($this->model)); + $reflectionProperty = $reflection->getProperty('tierPriceExtensionFactory'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->model, $factoryMock); + // test with the data retrieved as a REST object $tpRests = $this->model->getTierPrices($this->product); $this->assertNotNull($tpRests); $this->assertTrue(is_array($tpRests)); $this->assertEquals(sizeof($tps), sizeof($tpRests)); + foreach ($tpRests as $tpRest) { + $this->assertEquals(50, $tpRest->getExtensionAttributes()->getPercentageValue()); + } for ($i = 0; $i < sizeof($tps); $i++) { $this->assertEquals( diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/SimpleTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/SimpleTest.php index 01f33a5d5e9b1..eed4950221f22 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/SimpleTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/SimpleTest.php @@ -1,6 +1,6 @@ searchCriteriaBuilder = $this->getMock( + \Magento\Framework\Api\SearchCriteriaBuilder::class, + ['addFilters', 'create'], + [], + '', + false + ); + $this->filterBuilder = $this->getMock( + \Magento\Framework\Api\FilterBuilder::class, + ['setField', 'setConditionType', 'setValue', 'create'], + [], + '', + false + ); + $this->metadataPool = $this->getMock( + \Magento\Framework\EntityManager\MetadataPool::class, + ['getMetadata'], + [], + '', + false + ); + $this->productRepository = $this->getMockForAbstractClass( + \Magento\Catalog\Api\ProductRepositoryInterface::class, + [], + '', + false, + true, + true, + ['getList'] + ); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManager->getObject( + \Magento\Catalog\Model\ProductIdLocator::class, + [ + 'searchCriteriaBuilder' => $this->searchCriteriaBuilder, + 'filterBuilder' => $this->filterBuilder, + 'metadataPool' => $this->metadataPool, + 'productRepository' => $this->productRepository, + ] + ); + } + + /** + * Test retrieve + */ + public function testRetrieveProductIdsBySkus() + { + $skus = ['sku_1', 'sku_2']; + $searchCriteria = $this->getMock( + \Magento\Framework\Api\SearchCriteria::class, + [], + [], + '', + false + ); + $searchResults = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\ProductSearchResultsInterface::class, + [], + '', + false, + true, + true, + ['getItems'] + ); + $product = $this->getMockForAbstractClass( + \Magento\Catalog\Api\Data\ProductInterface::class, + [], + '', + false, + true, + true, + ['getSku', 'getData', 'getTypeId'] + ); + $metaDataInterface = $this->getMockForAbstractClass( + \Magento\Framework\EntityManager\EntityMetadataInterface::class, + [], + '', + false, + true, + true, + ['getLinkField'] + ); + $this->searchCriteriaBuilder->expects($this->once())->method('addFilters')->willReturnSelf(); + $this->filterBuilder->expects($this->once())->method('setField')->with('sku')->willReturnSelf(); + $this->filterBuilder->expects($this->once())->method('setConditionType')->with('in')->willReturnSelf(); + $this->filterBuilder->expects($this->once())->method('setValue')->with(['sku_1', 'sku_2'])->willReturnSelf(); + $this->filterBuilder->expects($this->once())->method('create')->willReturnSelf(); + $this->searchCriteriaBuilder + ->expects($this->once()) + ->method('create') + ->willReturn($searchCriteria); + $this->productRepository + ->expects($this->once()) + ->method('getList') + ->with($searchCriteria) + ->willReturn($searchResults); + $searchResults->expects($this->once())->method('getItems')->willReturn([$product]); + $this->metadataPool + ->expects($this->once()) + ->method('getMetadata') + ->with(\Magento\Catalog\Api\Data\ProductInterface::class) + ->willReturn($metaDataInterface); + $metaDataInterface->expects($this->once())->method('getLinkField')->willReturn('entity_id'); + $product->expects($this->once())->method('getSku')->willReturn('sku_1'); + $product->expects($this->once())->method('getData')->with('entity_id')->willReturn(1); + $product->expects($this->once())->method('getTypeId')->willReturn('simple'); + $this->assertEquals( + ['sku_1' => [1 => 'simple']], + $this->model->retrieveProductIdsBySkus($skus) + ); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php index d5ff3f580b457..4fb25b5927325 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductOptions/Config/_files/product_options_valid.xml b/app/code/Magento/Catalog/Test/Unit/Model/ProductOptions/Config/_files/product_options_valid.xml index 093521a0b7a49..5f418c4b177ad 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductOptions/Config/_files/product_options_valid.xml +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductOptions/Config/_files/product_options_valid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php index 5042ac1b745cf..a3f2372d48590 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php @@ -1,7 +1,7 @@ expects($this->any())->method('getWebsiteId')->willReturn('1'); $storeMock->expects($this->any())->method('getCode')->willReturn(\Magento\Store\Model\Store::ADMIN_CODE); $this->storeManagerMock->expects($this->any())->method('getStore')->willReturn($storeMock); - $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->mediaGalleryProcessor = $this->getMock( \Magento\Catalog\Model\Product\Gallery\Processor::class, @@ -495,6 +495,7 @@ public function testGetBySkuFromCacheInitializedInGetById() public function testSaveExisting() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->any())->method('getIdBySku')->will($this->returnValue(100)); $this->productFactoryMock->expects($this->any()) ->method('create') @@ -514,6 +515,7 @@ public function testSaveExisting() public function testSaveNew() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->at(0))->method('getIdBySku')->will($this->returnValue(null)); $this->resourceModelMock->expects($this->at(3))->method('getIdBySku')->will($this->returnValue(100)); $this->productFactoryMock->expects($this->any()) @@ -538,6 +540,7 @@ public function testSaveNew() */ public function testSaveUnableToSaveException() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->exactly(1))->method('getIdBySku')->will($this->returnValue(null)); $this->productFactoryMock->expects($this->exactly(2)) ->method('create') @@ -562,6 +565,7 @@ public function testSaveUnableToSaveException() */ public function testSaveException() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->exactly(1))->method('getIdBySku')->will($this->returnValue(null)); $this->productFactoryMock->expects($this->exactly(2)) ->method('create') @@ -587,6 +591,7 @@ public function testSaveException() */ public function testSaveInvalidProductException() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->exactly(1))->method('getIdBySku')->will($this->returnValue(null)); $this->productFactoryMock->expects($this->exactly(2)) ->method('create') @@ -610,6 +615,7 @@ public function testSaveInvalidProductException() */ public function testSaveThrowsTemporaryStateExceptionIfDatabaseConnectionErrorOccurred() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->productFactoryMock->expects($this->any()) ->method('create') ->will($this->returnValue($this->productMock)); @@ -709,6 +715,7 @@ public function testGetList() ->method('process') ->with($searchCriteriaMock, $collectionMock); $collectionMock->expects($this->once())->method('load'); + $collectionMock->expects($this->once())->method('addCategoryIds'); $collectionMock->expects($this->once())->method('getItems')->willReturn([$itemsMock]); $collectionMock->expects($this->once())->method('getSize')->willReturn(128); $searchResultsMock = $this->getMock( @@ -796,6 +803,7 @@ public function cacheKeyDataProvider() */ public function testSaveExistingWithOptions(array $newOptions, array $existingOptions, array $expectedData) { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->any())->method('getIdBySku')->will($this->returnValue(100)); $this->productFactoryMock->expects($this->any()) ->method('create') @@ -964,6 +972,7 @@ public function saveExistingWithOptionsDataProvider() */ public function testSaveWithLinks(array $newLinks, array $existingLinks, array $expectedData) { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->any())->method('getIdBySku')->will($this->returnValue(100)); $this->productFactoryMock->expects($this->any()) ->method('create') @@ -1143,6 +1152,7 @@ protected function setupProductMocksForSave() public function testSaveExistingWithNewMediaGalleryEntries() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $newEntriesData = [ [ "label" => "label_text", @@ -1222,8 +1232,48 @@ public function testSaveExistingWithNewMediaGalleryEntries() $this->model->save($this->productMock); } + public function websitesProvider() + { + return [ + [[1,2,3]] + ]; + } + + public function testSaveWithDifferentWebsites() + { + $storeMock = $this->getMock(StoreInterface::class); + $this->resourceModelMock->expects($this->at(0))->method('getIdBySku')->will($this->returnValue(null)); + $this->resourceModelMock->expects($this->at(3))->method('getIdBySku')->will($this->returnValue(100)); + $this->productFactoryMock->expects($this->any()) + ->method('create') + ->will($this->returnValue($this->productMock)); + $this->initializationHelperMock->expects($this->never())->method('initialize'); + $this->resourceModelMock->expects($this->once())->method('validate')->with($this->productMock) + ->willReturn(true); + $this->resourceModelMock->expects($this->once())->method('save')->with($this->productMock)->willReturn(true); + $this->extensibleDataObjectConverterMock + ->expects($this->once()) + ->method('toNestedArray') + ->will($this->returnValue($this->productData)); + $this->storeManagerMock->expects($this->any()) + ->method('getStore') + ->willReturn($storeMock); + $this->storeManagerMock->expects($this->once()) + ->method('getWebsites') + ->willReturn([ + 1 => ['first'], + 2 => ['second'], + 3 => ['third'] + ]); + $this->productMock->expects($this->once())->method('getWebsiteIds')->willReturn([1,2,3]); + $this->productMock->expects($this->once())->method('setWebsiteIds')->willReturn([2,3]); + + $this->assertEquals($this->productMock, $this->model->save($this->productMock)); + } + public function testSaveExistingWithMediaGalleryEntries() { + $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); //update one entry, delete one entry $newEntries = [ [ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php index d4950d9df6de7..2c44e0a50f983 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php @@ -1,6 +1,6 @@ [ - ['catalog_product_1'], + ['cat_p_1'], ['id' => 1, 'name' => 'value', 'category_ids' => [1]], ['id' => 1, 'name' => 'value', 'category_ids' => [1]], ], 'new product' => $this->getNewProductProviderData(), 'status and category change' => [ - [0 => 'catalog_product_1', 1 => 'catalog_category_product_1', 2 => 'catalog_category_product_2'], + [0 => 'cat_p_1', 1 => 'cat_c_p_1', 2 => 'cat_c_p_2'], ['id' => 1, 'name' => 'value', 'category_ids' => [1], 'status' => 2], [ 'id' => 1, @@ -726,18 +726,18 @@ public function getIdentitiesProvider() ], ], 'status change only' => [ - [0 => 'catalog_product_1', 1 => 'catalog_category_product_7'], + [0 => 'cat_p_1', 1 => 'cat_c_p_7'], ['id' => 1, 'name' => 'value', 'category_ids' => [7], 'status' => 1], ['id' => 1, 'name' => 'value', 'category_ids' => [7], 'status' => 2], ], 'status changed, category unassigned' => $this->getStatusAndCategoryChangesData(), 'no status changes' => [ - [0 => 'catalog_product_1'], + [0 => 'cat_p_1'], ['id' => 1, 'name' => 'value', 'category_ids' => [1], 'status' => 1], ['id' => 1, 'name' => 'value', 'category_ids' => [1], 'status' => 1], ], 'no stock status changes' => [ - [0 => 'catalog_product_1'], + [0 => 'cat_p_1'], ['id' => 1, 'name' => 'value', 'category_ids' => [1], 'status' => 1], [ 'id' => 1, @@ -749,7 +749,7 @@ public function getIdentitiesProvider() ], ], 'no stock status data 1' => [ - [0 => 'catalog_product_1'], + [0 => 'cat_p_1'], ['id' => 1, 'name' => 'value', 'category_ids' => [1], 'status' => 1], [ 'id' => 1, @@ -760,7 +760,7 @@ public function getIdentitiesProvider() ], ], 'no stock status data 2' => [ - [0 => 'catalog_product_1'], + [0 => 'cat_p_1'], ['id' => 1, 'name' => 'value', 'category_ids' => [1], 'status' => 1], [ 'id' => 1, @@ -780,7 +780,7 @@ public function getIdentitiesProvider() private function getStatusAndCategoryChangesData() { return [ - [0 => 'catalog_product_1', 1 => 'catalog_category_product_5'], + [0 => 'cat_p_1', 1 => 'cat_c_p_5'], ['id' => 1, 'name' => 'value', 'category_ids' => [5], 'status' => 2], [ 'id' => 1, @@ -799,7 +799,7 @@ private function getStatusAndCategoryChangesData() private function getNewProductProviderData() { return [ - ['catalog_product_1', 'catalog_category_product_1'], + ['cat_p_1', 'cat_c_p_1'], null, [ 'id' => 1, @@ -818,7 +818,7 @@ private function getNewProductProviderData() private function getStatusStockProviderData($extensionAttributesMock) { return [ - [0 => 'catalog_product_1', 1 => 'catalog_category_product_1'], + [0 => 'cat_p_1', 1 => 'cat_c_p_1'], ['id' => 1, 'name' => 'value', 'category_ids' => [1], 'status' => 1], [ 'id' => 1, @@ -831,20 +831,6 @@ private function getStatusStockProviderData($extensionAttributesMock) ]; } - public function testStatusAfterLoad() - { - $this->resource->expects($this->once())->method('load')->with($this->model, 1, null); - $this->eventManagerMock->expects($this->exactly(4))->method('dispatch'); - $this->model->load(1); - $this->assertEquals( - Status::STATUS_ENABLED, - $this->model->getData(\Magento\Catalog\Model\Product::STATUS) - ); - $this->assertFalse($this->model->hasDataChanges()); - $this->model->setStatus(Status::STATUS_DISABLED); - $this->assertTrue($this->model->hasDataChanges()); - } - /** * Test retrieving price Info */ @@ -1467,4 +1453,27 @@ public function testGetTypeId() $this->model->setTypeId('typeId'); $this->model->getTypeInstance(); } + + public function testGetOptionById() + { + $optionId = 100; + $optionMock = $this->getMock(\Magento\Catalog\Model\Product\Option::class, [], [], '', false); + $this->model->setOptions([$optionMock]); + $optionMock->expects($this->once())->method('getId')->willReturn($optionId); + $this->assertEquals($optionMock, $this->model->getOptionById($optionId)); + } + + public function testGetOptionByIdWithWrongOptionId() + { + $optionId = 100; + $optionMock = $this->getMock(\Magento\Catalog\Model\Product\Option::class, [], [], '', false); + $this->model->setOptions([$optionMock]); + $optionMock->expects($this->once())->method('getId')->willReturn(200); + $this->assertNull($this->model->getOptionById($optionId)); + } + + public function testGetOptionByIdForProductWithoutOptions() + { + $this->assertNull($this->model->getOptionById(100)); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypeListTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypeListTest.php index 63254a653ab35..6b0bea2c191f3 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypeListTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypeListTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types.xml b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types.xml index 525beaf93c6e9..dc5284d1e5405 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types.xml +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types_merged.xml b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types_merged.xml index 96a8c06c1db2a..724203272620b 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types_merged.xml +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/Config/_files/valid_product_types_merged.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/ConfigTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/ConfigTest.php index af0c1625f9cb6..64b8b05b5755d 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/ConfigTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTypes/ConfigTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->readerMock = $this->getMock( \Magento\Catalog\Model\ProductTypes\Config\Reader::class, [], @@ -32,19 +43,35 @@ protected function setUp() false ); $this->cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); } /** - * @dataProvider getTypeDataProvider - * * @param array $value * @param mixed $expected + * @dataProvider getTypeDataProvider */ public function testGetType($value, $expected) { - $this->cacheMock->expects($this->any())->method('load')->will($this->returnValue(serialize($value))); - $this->model = new \Magento\Catalog\Model\ProductTypes\Config($this->readerMock, $this->cacheMock, 'cache_id'); - $this->assertEquals($expected, $this->model->getType('global')); + $this->cacheMock->expects($this->any()) + ->method('load') + ->willReturn('serializedData'); + + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn($value); + + $this->config = $this->objectManager->getObject( + \Magento\Catalog\Model\ProductTypes\Config::class, + [ + 'reader' => $this->readerMock, + 'cache' => $this->cacheMock, + 'cacheId' => 'cache_id', + 'serializer' => $this->serializerMock, + ] + ); + $this->assertEquals($expected, $this->config->getType('global')); } public function getTypeDataProvider() @@ -58,22 +85,43 @@ public function getTypeDataProvider() public function testGetAll() { $expected = ['Expected Data']; - $this->cacheMock->expects( - $this->once() - )->method( - 'load' - )->will( - $this->returnValue(serialize(['types' => $expected])) + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn(json_encode('"types":["Expected Data"]]')); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn(['types' => $expected]); + + $this->config = $this->objectManager->getObject( + \Magento\Catalog\Model\ProductTypes\Config::class, + [ + 'reader' => $this->readerMock, + 'cache' => $this->cacheMock, + 'cacheId' => 'cache_id', + 'serializer' => $this->serializerMock, + ] ); - $this->model = new \Magento\Catalog\Model\ProductTypes\Config($this->readerMock, $this->cacheMock, 'cache_id'); - $this->assertEquals($expected, $this->model->getAll()); + $this->assertEquals($expected, $this->config->getAll()); } public function testIsProductSet() { - $this->cacheMock->expects($this->once())->method('load')->will($this->returnValue(serialize([]))); - $this->model = new \Magento\Catalog\Model\ProductTypes\Config($this->readerMock, $this->cacheMock, 'cache_id'); + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn(''); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn([]); - $this->assertEquals(false, $this->model->isProductSet('typeId')); + $this->config = $this->objectManager->getObject( + \Magento\Catalog\Model\ProductTypes\Config::class, + [ + 'reader' => $this->readerMock, + 'cache' => $this->cacheMock, + 'cacheId' => 'cache_id', + 'serializer' => $this->serializerMock, + ] + ); + $this->assertEquals(false, $this->config->isProductSet('typeId')); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/AbstractTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/AbstractTest.php index 044bb6cfc9033..e7b7926edc562 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/AbstractTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/AbstractTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $entityFactory = $this->getMock(\Magento\Framework\Data\Collection\EntityFactory::class, [], [], '', false); $logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) ->disableOriginalConstructor() @@ -100,27 +123,39 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $entityMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class) + $this->entityMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class) ->disableOriginalConstructor() ->getMock(); + $this->galleryResourceMock = $this->getMockBuilder( + \Magento\Catalog\Model\ResourceModel\Product\Gallery::class + )->disableOriginalConstructor()->getMock(); + + $this->metadataPoolMock = $this->getMockBuilder( + \Magento\Framework\EntityManager\MetadataPool::class + )->disableOriginalConstructor()->getMock(); + + $this->galleryReadHandlerMock = $this->getMockBuilder( + \Magento\Catalog\Model\Product\Gallery\ReadHandler::class + )->disableOriginalConstructor()->getMock(); + $storeManager->expects($this->any())->method('getId')->willReturn(1); $storeManager->expects($this->any())->method('getStore')->willReturnSelf(); $universalFactory->expects($this->exactly(1))->method('create')->willReturnOnConsecutiveCalls( - $entityMock + $this->entityMock ); - $entityMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock); - $entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn([]); - $entityMock->expects($this->any())->method('getTable')->willReturnArgument(0); + $this->entityMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock); + $this->entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn([]); + $this->entityMock->expects($this->any())->method('getTable')->willReturnArgument(0); $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock); - $helper = new ObjectManager($this); - $this->prepareObjectManager([ - [\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class, - $this->getMock(\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class) - ] - ]); - $this->collection = $helper->getObject( + $productLimitationMock = $this->getMock( + \Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class + ); + $productLimitationFactoryMock = $this->getMock(ProductLimitationFactory::class, ['create']); + $productLimitationFactoryMock->method('create') + ->willReturn($productLimitationMock); + $this->collection = $this->objectManager->getObject( \Magento\Catalog\Model\ResourceModel\Product\Collection::class, [ 'entityFactory' => $entityFactory, @@ -142,16 +177,28 @@ protected function setUp() 'customerSession' => $customerSession, 'dateTime' => $dateTime, 'groupManagement' => $groupManagement, - 'connection' => $this->connectionMock + 'connection' => $this->connectionMock, + 'productLimitationFactory' => $productLimitationFactoryMock, + 'metadataPool' => $this->metadataPoolMock, ] ); $this->collection->setConnection($this->connectionMock); + $this->objectManager->setBackwardCompatibleProperty( + $this->collection, + 'mediaGalleryResource', + $this->galleryResourceMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->collection, + 'productGalleryReadHandler', + $this->galleryReadHandlerMock + ); } public function testAddProductCategoriesFilter() { - $condition = ['in' => [1,2]]; - $values = [1,2]; + $condition = ['in' => [1, 2]]; + $values = [1, 2]; $conditionType = 'nin'; $preparedSql = "category_id IN(1,2)"; $tableName = "catalog_category_product"; @@ -174,19 +221,45 @@ public function testAddProductCategoriesFilter() $this->collection->addCategoriesFilter([$conditionType => $values]); } - /** - * @param $map - */ - private function prepareObjectManager($map) + public function testAddMediaGalleryData() { - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); - $objectManagerMock->expects($this->any())->method('getInstance')->willReturnSelf(); - $objectManagerMock->expects($this->any()) - ->method('get') - ->will($this->returnValueMap($map)); - $reflectionClass = new \ReflectionClass(\Magento\Framework\App\ObjectManager::class); - $reflectionProperty = $reflectionClass->getProperty('_instance'); + $attributeId = 42; + $rowId = 4; + $linkField = 'row_id'; + $mediaGalleriesMock = [[$linkField => $rowId]]; + $itemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->setMethods(['getData']) + ->getMock(); + $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->disableOriginalConstructor() + ->getMock(); + $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class) + ->disableOriginalConstructor() + ->getMock(); + $metadataMock = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->collection->addItem($itemMock); + $reflection = new \ReflectionClass(get_class($this->collection)); + $reflectionProperty = $reflection->getProperty('_isCollectionLoaded'); $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($objectManagerMock); + $reflectionProperty->setValue($this->collection, true); + + $this->galleryResourceMock->expects($this->once())->method('createBatchBaseSelect')->willReturn($selectMock); + $attributeMock->expects($this->once())->method('getAttributeId')->willReturn($attributeId); + $this->entityMock->expects($this->once())->method('getAttribute')->willReturn($attributeMock); + $itemMock->expects($this->atLeastOnce())->method('getData')->willReturn($rowId); + $selectMock->expects($this->once())->method('where')->with('entity.' . $linkField . ' IN (?)', [$rowId]); + $this->metadataPoolMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock); + $metadataMock->expects($this->once())->method('getLinkField')->willReturn($linkField); + + $this->connectionMock->expects($this->once())->method('fetchAll')->with($selectMock)->willReturn( + [['row_id' => $rowId]] + ); + $this->galleryReadHandlerMock->expects($this->once())->method('addMediaDataToProduct') + ->with($itemMock, $mediaGalleriesMock); + + $this->assertSame($this->collection, $this->collection->addMediaGalleryData()); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CompositeBaseSelectProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CompositeBaseSelectProcessorTest.php new file mode 100644 index 0000000000000..30060c81883eb --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CompositeBaseSelectProcessorTest.php @@ -0,0 +1,54 @@ +objectManager = new ObjectManager($this); + } + + /** + * @expectedException \Magento\Framework\Exception\InputException + */ + public function testInitializeWithWrongProcessorInstance() + { + $processorValid = $this->getMock(BaseSelectProcessorInterface::class); + $processorInvalid = $this->getMock(\stdClass::class); + + $this->objectManager->getObject(CompositeBaseSelectProcessor::class, [ + 'baseSelectProcessors' => [$processorValid, $processorInvalid], + ]); + } + + public function testProcess() + { + $select = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock(); + + $processorFirst = $this->getMock(BaseSelectProcessorInterface::class); + $processorFirst->expects($this->once())->method('process')->with($select)->willReturn($select); + + $processorSecond = $this->getMock(BaseSelectProcessorInterface::class); + $processorSecond->expects($this->once())->method('process')->with($select)->willReturn($select); + + /** @var CompositeBaseSelectProcessor $baseSelectProcessors */ + $baseSelectProcessors = $this->objectManager->getObject(CompositeBaseSelectProcessor::class, [ + 'baseSelectProcessors' => [$processorFirst, $processorSecond], + ]); + $this->assertEquals($select, $baseSelectProcessors->process($select)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/FlatTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/FlatTest.php index a05a627693260..8fed73a4d007a 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/FlatTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/FlatTest.php @@ -1,6 +1,6 @@ resource->deleteGalleryValueInStore($valueId, $entityId, $storeId); } + + public function testCountImageUses() + { + $results = [ + [ + 'value_id' => '1', + 'attribute_id' => 90, + 'value' => '/d/o/download_7.jpg', + 'media_type' => 'image', + 'disabled' => '0', + ], + ]; + + $this->connection->expects($this->once())->method('select')->will($this->returnValue($this->select)); + $this->select->expects($this->at(0))->method('from')->with( + [ + 'main' => 'table', + ], + '*' + )->willReturnSelf(); + $this->select->expects($this->at(1))->method('where')->with( + 'value = ?', + 1 + )->willReturnSelf(); + $this->connection->expects($this->once())->method('fetchAll') + ->with($this->select) + ->willReturn($results); + $this->assertEquals($this->resource->countImageUses(1), count($results)); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php index 3c92cde30012d..bb7250a904f61 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Link/Product/CollectionTest.php @@ -1,12 +1,12 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->entityFactoryMock = $this->getMock( \Magento\Framework\Data\Collection\EntityFactory::class, [], @@ -133,14 +134,11 @@ function ($store) { $this->timezoneInterfaceMock = $this->getMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class); $this->sessionMock = $this->getMock(\Magento\Customer\Model\Session::class, [], [], '', false); $this->dateTimeMock = $this->getMock(\Magento\Framework\Stdlib\DateTime::class); - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->prepareObjectManager([ - [\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class, - $this->getMock(\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class) - ] - ]); + $productLimitationFactoryMock = $this->getMock(ProductLimitationFactory::class, ['create']); + $productLimitationFactoryMock->method('create') + ->willReturn($this->getMock(ProductLimitation::class)); - $this->collection = $this->objectManagerHelper->getObject( + $this->collection = $this->objectManager->getObject( \Magento\Catalog\Model\ResourceModel\Product\Link\Product\Collection::class, [ 'entityFactory' => $this->entityFactoryMock, @@ -160,7 +158,8 @@ function ($store) { 'catalogUrl' => $this->urlMock, 'localeDate' => $this->timezoneInterfaceMock, 'customerSession' => $this->sessionMock, - 'dateTime' => $this->dateTimeMock + 'dateTime' => $this->dateTimeMock, + 'productLimitationFactory' => $productLimitationFactoryMock, ] ); } @@ -175,20 +174,4 @@ public function testSetProduct() $this->collection->setProduct($product); $this->assertEquals(33, $this->collection->getStoreId()); } - - /** - * @param $map - */ - public function prepareObjectManager($map) - { - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); - $objectManagerMock->expects($this->any())->method('getInstance')->willReturnSelf(); - $objectManagerMock->expects($this->any()) - ->method('get') - ->will($this->returnValueMap($map)); - $reflectionClass = new \ReflectionClass(\Magento\Framework\App\ObjectManager::class); - $reflectionProperty = $reflectionClass->getProperty('_instance'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($objectManagerMock); - } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/LinkTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/LinkTest.php index 50f14246ed9ee..b9fb5a717c8c7 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/LinkTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/LinkTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->entityFactoryMock = $this->getMock( \Magento\Framework\Data\Collection\EntityFactory::class, ['create'], [], '', false ); @@ -147,11 +150,6 @@ protected function setUp() $this->metadataPoolMock->expects($this->any())->method('getMetadata')->willReturn($metadata); $this->selectMock->expects($this->exactly(2))->method('join'); - $this->prepareObjectManager([ - [\Magento\Framework\EntityManager\MetadataPool::class, $this->metadataPoolMock], - [\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface::class, $this->joinProcessor] - ]); - $this->collection = new Collection( $this->entityFactoryMock, $this->loggerMock, @@ -160,7 +158,13 @@ protected function setUp() $this->optionsFactoryMock, $this->storeManagerMock, null, - $this->resourceMock + $this->resourceMock, + $this->metadataPoolMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->collection, + 'joinProcessor', + $this->joinProcessor ); } @@ -168,20 +172,4 @@ public function testReset() { $this->collection->reset(); } - - /** - * @param $map - */ - private function prepareObjectManager($map) - { - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); - $objectManagerMock->expects($this->any())->method('getInstance')->willReturnSelf(); - $objectManagerMock->expects($this->any()) - ->method('get') - ->will($this->returnValueMap($map)); - $reflectionClass = new \ReflectionClass(\Magento\Framework\App\ObjectManager::class); - $reflectionProperty = $reflectionClass->getProperty('_instance'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($objectManagerMock); - } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php new file mode 100644 index 0000000000000..0a828a9106dff --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/StatusBaseSelectProcessorTest.php @@ -0,0 +1,129 @@ +eavConfig = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock(); + $this->metadataPool = $this->getMockBuilder(MetadataPool::class)->disableOriginalConstructor()->getMock(); + $this->storeResolver = $this->getMockBuilder(StoreResolverInterface::class)->getMock(); + $this->select = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock(); + + $this->statusBaseSelectProcessor = (new ObjectManager($this))->getObject(StatusBaseSelectProcessor::class, [ + 'eavConfig' => $this->eavConfig, + 'metadataPool' => $this->metadataPool, + 'storeResolver' => $this->storeResolver, + ]); + } + + public function testProcess() + { + $linkField = 'link_field'; + $backendTable = 'backend_table'; + $attributeId = 2; + $currentStoreId = 1; + + $metadata = $this->getMock(EntityMetadataInterface::class); + $metadata->expects($this->once()) + ->method('getLinkField') + ->willReturn($linkField); + $this->metadataPool->expects($this->once()) + ->method('getMetadata') + ->with(ProductInterface::class) + ->willReturn($metadata); + + /** @var AttributeInterface|\PHPUnit_Framework_MockObject_MockObject $statusAttribute */ + $statusAttribute = $this->getMockBuilder(AttributeInterface::class) + ->setMethods(['getBackendTable', 'getAttributeId']) + ->getMock(); + $statusAttribute->expects($this->atLeastOnce()) + ->method('getBackendTable') + ->willReturn($backendTable); + $statusAttribute->expects($this->atLeastOnce()) + ->method('getAttributeId') + ->willReturn($attributeId); + $this->eavConfig->expects($this->once()) + ->method('getAttribute') + ->with(Product::ENTITY, ProductInterface::STATUS) + ->willReturn($statusAttribute); + + $this->storeResolver->expects($this->once()) + ->method('getCurrentStoreId') + ->willReturn($currentStoreId); + + $this->select->expects($this->at(0)) + ->method('joinLeft') + ->with( + ['status_global_attr' => $backendTable], + "status_global_attr.{$linkField} = " + . BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS . ".{$linkField}" + . " AND status_global_attr.attribute_id = {$attributeId}" + . ' AND status_global_attr.store_id = ' . Store::DEFAULT_STORE_ID, + [] + ) + ->willReturnSelf(); + $this->select->expects($this->at(1)) + ->method('joinLeft') + ->with( + ['status_attr' => $backendTable], + "status_attr.{$linkField} = " . BaseSelectProcessorInterface::PRODUCT_TABLE_ALIAS . ".{$linkField}" + . " AND status_attr.attribute_id = {$attributeId}" + . " AND status_attr.store_id = {$currentStoreId}", + [] + ) + ->willReturnSelf(); + $this->select->expects($this->at(2)) + ->method('where') + ->with('IFNULL(status_attr.value, status_global_attr.value) = ?', Status::STATUS_ENABLED) + ->willReturnSelf(); + + $this->assertEquals($this->select, $this->statusBaseSelectProcessor->process($this->select)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Website/LinkTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Website/LinkTest.php index bedeba40eefcf..a01fbc4d2e386 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Website/LinkTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/Website/LinkTest.php @@ -1,6 +1,6 @@ mediaConfig = $this->getMockBuilder(ConfigInterface::class)->getMockForAbstractClass(); + $this->mediaConfig->expects($this->any())->method('getBaseMediaPath')->willReturn('catalog/product'); + $this->mediaDirectory = $this->getMockBuilder(WriteInterface::class)->getMockForAbstractClass(); + $this->mediaDirectory->expects($this->once())->method('create')->with('catalog/product'); + $this->filesystem = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + $this->filesystem->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::MEDIA) + ->willReturn($this->mediaDirectory); + $this->model = new Context( + $this->mediaConfig, + $this->filesystem + ); + } + + public function testGetPath() + { + $path = '/var/www/html/magento2ce/pub/media/catalog/product'; + $this->mediaDirectory->expects($this->once()) + ->method('getAbsolutePath') + ->with('catalog/product') + ->willReturn($path); + + $this->assertEquals($path, $this->model->getPath()); + } + + public function testGetUrl() + { + $baseUrl = 'http://localhost/pub/media/catalog/product'; + $this->mediaConfig->expects($this->once())->method('getBaseMediaUrl')->willReturn($baseUrl); + + $this->assertEquals($baseUrl, $this->model->getBaseUrl()); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/View/Asset/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/View/Asset/ImageTest.php new file mode 100644 index 0000000000000..1459a9c2f49e4 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/View/Asset/ImageTest.php @@ -0,0 +1,148 @@ +mediaConfig = $this->getMockBuilder(ConfigInterface::class)->getMockForAbstractClass(); + $this->encryptor = $this->getMockBuilder(EncryptorInterface::class)->getMockForAbstractClass(); + $this->imageContext = $this->getMockBuilder(ContextInterface::class)->getMockForAbstractClass(); + $this->model = new Image( + $this->mediaConfig, + $this->imageContext, + $this->encryptor, + '/somefile.png' + ); + } + + public function testModuleAndContentAndContentType() + { + $contentType = 'image'; + $this->assertEquals($contentType, $this->model->getContentType()); + $this->assertEquals($contentType, $this->model->getSourceContentType()); + $this->assertNull($this->model->getContent()); + $this->assertEquals('cache', $this->model->getModule()); + } + + public function testGetFilePath() + { + $this->assertEquals('/somefile.png', $this->model->getFilePath()); + } + + public function testGetSoureFile() + { + $this->mediaConfig->expects($this->once())->method('getBaseMediaPath')->willReturn('catalog/product'); + $this->assertEquals('catalog/product/somefile.png', $this->model->getSourceFile()); + } + + public function testGetContext() + { + $this->assertInstanceOf(ContextInterface::class, $this->model->getContext()); + } + + /** + * @param string $filePath + * @param array $miscParams + * @dataProvider getPathDataProvider + */ + public function testGetPath($filePath, $miscParams) + { + $imageModel = new Image( + $this->mediaConfig, + $this->imageContext, + $this->encryptor, + $filePath, + $miscParams + ); + $absolutePath = '/var/www/html/magento2ce/pub/media/catalog/product'; + $hashPath = md5(implode('_', $miscParams)); + $this->imageContext->expects($this->once())->method('getPath')->willReturn($absolutePath); + $this->encryptor->expects($this->once())->method('hash')->willReturn($hashPath); + $this->assertEquals( + $absolutePath . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . $hashPath . $filePath, + $imageModel->getPath() + ); + } + + /** + * @param string $filePath + * @param array $miscParams + * @dataProvider getPathDataProvider + */ + public function testGetUrl($filePath, $miscParams) + { + $imageModel = new Image( + $this->mediaConfig, + $this->imageContext, + $this->encryptor, + $filePath, + $miscParams + ); + $absolutePath = 'http://localhost/pub/media/catalog/product'; + $hashPath = md5(implode('_', $miscParams)); + $this->imageContext->expects($this->once())->method('getBaseUrl')->willReturn($absolutePath); + $this->encryptor->expects($this->once())->method('hash')->willReturn($hashPath); + $this->assertEquals( + $absolutePath . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . $hashPath . $filePath, + $imageModel->getUrl() + ); + } + + public function getPathDataProvider() + { + return [ + [ + '/some_file.png', + [], //default value for miscParams + ], + [ + '/some_file_2.png', + [ + 'image_type' => 'thumbnail', + 'image_height' => 75, + 'image_width' => 75, + 'keep_aspect_ratio' => 'proportional', + 'keep_frame' => 'frame', + 'keep_transparency' => 'transparency', + 'constrain_only' => 'doconstrainonly', + 'background' => 'ffffff', + 'angle' => null, + 'quality' => 80, + ], + ] + ]; + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/View/Asset/PlaceholderTest.php b/app/code/Magento/Catalog/Test/Unit/Model/View/Asset/PlaceholderTest.php new file mode 100644 index 0000000000000..ec45cd6f72127 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/View/Asset/PlaceholderTest.php @@ -0,0 +1,163 @@ +scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class)->getMockForAbstractClass(); + $this->imageContext = $this->getMockBuilder(ContextInterface::class)->getMockForAbstractClass(); + $this->repository = $this->getMockBuilder(Repository::class)->disableOriginalConstructor()->getMock(); + $this->model = new Placeholder( + $this->imageContext, + $this->scopeConfig, + $this->repository, + 'thumbnail' + ); + } + + public function testModuleAndContentAndContentType() + { + $contentType = 'image'; + $this->assertEquals($contentType, $this->model->getContentType()); + $this->assertEquals($contentType, $this->model->getSourceContentType()); + $this->assertNull($this->model->getContent()); + $this->assertEquals('placeholder', $this->model->getModule()); + } + + public function testGetFilePath() + { + $this->assertNull($this->model->getFilePath()); + $this->scopeConfig->expects($this->once())->method('getValue')->willReturn('default/thumbnail.jpg'); + $this->assertEquals('default/thumbnail.jpg', $this->model->getFilePath()); + } + + public function testGetContext() + { + $this->assertInstanceOf(ContextInterface::class, $this->model->getContext()); + } + + /** + * @param string $imageType + * @param string $placeholderPath + * @dataProvider getPathDataProvider + */ + public function testGetPathAndGetSourceFile($imageType, $placeholderPath) + { + $imageModel = new Placeholder( + $this->imageContext, + $this->scopeConfig, + $this->repository, + $imageType + ); + $absolutePath = '/var/www/html/magento2ce/pub/media/catalog/product'; + + $this->scopeConfig->expects($this->any()) + ->method('getValue') + ->with( + "catalog/placeholder/{$imageType}_placeholder", + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + null + )->willReturn($placeholderPath); + + if ($placeholderPath == null) { + $this->imageContext->expects($this->never())->method('getPath'); + $assetMock = $this->getMockBuilder(\Magento\Framework\View\Asset\MergeableInterface::class) + ->getMockForAbstractClass(); + $expectedResult = 'path/to_default/placeholder/by_type'; + $assetMock->expects($this->any())->method('getSourceFile')->willReturn($expectedResult); + $this->repository->expects($this->any())->method('createAsset')->willReturn($assetMock); + } else { + $this->imageContext->expects($this->any())->method('getPath')->willReturn($absolutePath); + $expectedResult = $absolutePath + . DIRECTORY_SEPARATOR . $imageModel->getModule() + . DIRECTORY_SEPARATOR . $placeholderPath; + } + + $this->assertEquals($expectedResult, $imageModel->getPath()); + $this->assertEquals($expectedResult, $imageModel->getSourceFile()); + } + + /** + * @param string $imageType + * @param string $placeholderPath + * @dataProvider getPathDataProvider + */ + public function testGetUrl($imageType, $placeholderPath) + { + $imageModel = new Placeholder( + $this->imageContext, + $this->scopeConfig, + $this->repository, + $imageType + ); + + $this->scopeConfig->expects($this->any()) + ->method('getValue') + ->with( + "catalog/placeholder/{$imageType}_placeholder", + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + null + )->willReturn($placeholderPath); + + if ($placeholderPath == null) { + $this->imageContext->expects($this->never())->method('getBaseUrl'); + $expectedResult = 'http://localhost/pub/media/catalog/product/to_default/placeholder/by_type'; + $this->repository->expects($this->any())->method('getUrl')->willReturn($expectedResult); + } else { + $baseUrl = 'http://localhost/pub/media/catalog/product'; + $this->imageContext->expects($this->any())->method('getBaseUrl')->willReturn($baseUrl); + $expectedResult = $baseUrl + . DIRECTORY_SEPARATOR . $imageModel->getModule() + . DIRECTORY_SEPARATOR . $placeholderPath; + } + + $this->assertEquals($expectedResult, $imageModel->getUrl()); + } + + public function getPathDataProvider() + { + return [ + [ + 'thumbnail', + 'default/thumbnail.jpg', + ], + [ + 'non_exist', + null, + ], + ]; + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/_files/converted_view.php b/app/code/Magento/Catalog/Test/Unit/Model/_files/converted_view.php index 49d865253ced4..d173b9dc05a32 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/_files/converted_view.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/_files/converted_view.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/Test/Unit/Observer/MenuCategoryDataTest.php b/app/code/Magento/Catalog/Test/Unit/Observer/MenuCategoryDataTest.php index fde1c74bc5ae5..a935861a263e1 100644 --- a/app/code/Magento/Catalog/Test/Unit/Observer/MenuCategoryDataTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Observer/MenuCategoryDataTest.php @@ -1,6 +1,6 @@ cache = $this->getMock(\Magento\Framework\App\CacheInterface::class); $this->cacheState = $this->getMock(\Magento\Framework\App\Cache\StateInterface::class); + $this->serializer = $this->getMock(SerializerInterface::class); $this->subject = $this->getMock(\Magento\Catalog\Model\ResourceModel\Config::class, [], [], '', false); } @@ -47,12 +50,17 @@ public function testGetAttributesUsedInListingFromCache() $entityTypeId = 'type'; $storeId = 'store'; $attributes = ['attributes']; + $serializedAttributes = '["attributes"]'; $this->subject->expects($this->any())->method('getEntityTypeId')->willReturn($entityTypeId); $this->subject->expects($this->any())->method('getStoreId')->willReturn($storeId); $cacheId = \Magento\Catalog\Plugin\Model\ResourceModel\Config::PRODUCT_LISTING_ATTRIBUTES_CACHE_ID . $entityTypeId . '_' . $storeId; - $this->cache->expects($this->any())->method('load')->with($cacheId)->willReturn(serialize($attributes)); + $this->cache->expects($this->any())->method('load')->with($cacheId)->willReturn($serializedAttributes); + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($serializedAttributes) + ->willReturn($attributes); $this->assertEquals( $attributes, @@ -68,14 +76,21 @@ public function testGetAttributesUsedInListingWithCacheSave() $entityTypeId = 'type'; $storeId = 'store'; $attributes = ['attributes']; + $serializedAttributes = '["attributes"]'; $this->subject->expects($this->any())->method('getEntityTypeId')->willReturn($entityTypeId); $this->subject->expects($this->any())->method('getStoreId')->willReturn($storeId); $cacheId = \Magento\Catalog\Plugin\Model\ResourceModel\Config::PRODUCT_LISTING_ATTRIBUTES_CACHE_ID . $entityTypeId . '_' . $storeId; $this->cache->expects($this->any())->method('load')->with($cacheId)->willReturn(false); + $this->serializer->expects($this->never()) + ->method('unserialize'); + $this->serializer->expects($this->once()) + ->method('serialize') + ->with($attributes) + ->willReturn($serializedAttributes); $this->cache->expects($this->any())->method('save')->with( - serialize($attributes), + $serializedAttributes, $cacheId, [ \Magento\Eav\Model\Cache\Type::CACHE_TAG, @@ -110,11 +125,16 @@ public function testGetAttributesUsedForSortByFromCache() $entityTypeId = 'type'; $storeId = 'store'; $attributes = ['attributes']; + $serializedAttributes = '["attributes"]'; $this->subject->expects($this->any())->method('getEntityTypeId')->willReturn($entityTypeId); $this->subject->expects($this->any())->method('getStoreId')->willReturn($storeId); $cacheId = \Magento\Catalog\Plugin\Model\ResourceModel\Config::PRODUCT_LISTING_SORT_BY_ATTRIBUTES_CACHE_ID . $entityTypeId . '_' . $storeId; - $this->cache->expects($this->any())->method('load')->with($cacheId)->willReturn(serialize($attributes)); + $this->cache->expects($this->any())->method('load')->with($cacheId)->willReturn($serializedAttributes); + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($serializedAttributes) + ->willReturn($attributes); $this->assertEquals( $attributes, @@ -130,13 +150,20 @@ public function testGetAttributesUsedForSortByWithCacheSave() $entityTypeId = 'type'; $storeId = 'store'; $attributes = ['attributes']; + $serializedAttributes = '["attributes"]'; $this->subject->expects($this->any())->method('getEntityTypeId')->willReturn($entityTypeId); $this->subject->expects($this->any())->method('getStoreId')->willReturn($storeId); $cacheId = \Magento\Catalog\Plugin\Model\ResourceModel\Config::PRODUCT_LISTING_SORT_BY_ATTRIBUTES_CACHE_ID . $entityTypeId . '_' . $storeId; $this->cache->expects($this->any())->method('load')->with($cacheId)->willReturn(false); + $this->serializer->expects($this->never()) + ->method('unserialize'); + $this->serializer->expects($this->once()) + ->method('serialize') + ->with($attributes) + ->willReturn($serializedAttributes); $this->cache->expects($this->any())->method('save')->with( - serialize($attributes), + $serializedAttributes, $cacheId, [ \Magento\Eav\Model\Cache\Type::CACHE_TAG, @@ -165,7 +192,8 @@ protected function getConfig($cacheEnabledFlag) \Magento\Catalog\Plugin\Model\ResourceModel\Config::class, [ 'cache' => $this->cache, - 'cacheState' => $this->cacheState + 'cacheState' => $this->cacheState, + 'serializer' => $this->serializer, ] ); } diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/BasePriceTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/BasePriceTest.php index 3cb1749dc4add..11ff04d0aa0fb 100644 --- a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/BasePriceTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/BasePriceTest.php @@ -1,6 +1,6 @@ price = $this->getMock(TierPrice::class, [], [], '', false); + $this->priceInfo = $this->getMockForAbstractClass(PriceInfoInterface::class); + $this->saleable = $this->getMockForAbstractClass(SaleableInterface::class); + + $this->objectManager = new ObjectManager($this); + + $this->calculator = $this->getMockForAbstractClass(CalculatorInterface::class); + $this->object = $this->objectManager->getObject( + MinimalTierPriceCalculator::class, + ['calculator' => $this->calculator] + ); + } + + private function getValueTierPricesExistShouldReturnMinTierPrice() + { + $minPrice = 5; + $notMinPrice = 10; + + $minAmount = $this->getMockForAbstractClass(AmountInterface::class); + $minAmount->expects($this->once())->method('getValue')->willReturn($minPrice); + + $notMinAmount = $this->getMockForAbstractClass(AmountInterface::class); + $notMinAmount->expects($this->once())->method('getValue')->willReturn($notMinPrice); + + $tierPriceList = [ + [ + 'price' => $minAmount + ], + [ + 'price' => $notMinAmount + ] + ]; + + $this->price->expects($this->once())->method('getTierPriceList')->willReturn($tierPriceList); + + $this->priceInfo->expects($this->once())->method('getPrice')->with(TierPrice::PRICE_CODE) + ->willReturn($this->price); + + $this->saleable->expects($this->once())->method('getPriceInfo')->willReturn($this->priceInfo); + return $minPrice; + } + + public function testGetValueTierPricesExistShouldReturnMinTierPrice() + { + $minPrice = $this->getValueTierPricesExistShouldReturnMinTierPrice(); + $this->assertEquals($minPrice, $this->object->getValue($this->saleable)); + } + + public function testGetGetAmountMinTierPriceExistShouldReturnAmountObject() + { + $minPrice = $this->getValueTierPricesExistShouldReturnMinTierPrice(); + + $amount = $this->getMockForAbstractClass(AmountInterface::class); + + $this->calculator->expects($this->once()) + ->method('getAmount') + ->with($minPrice, $this->saleable) + ->willReturn($amount); + + $this->assertSame($amount, $this->object->getAmount($this->saleable)); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/RegularPriceTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/RegularPriceTest.php index 09988088c1632..54259101469bd 100644 --- a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/RegularPriceTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/RegularPriceTest.php @@ -1,6 +1,6 @@ product = $this->getMock( \Magento\Catalog\Model\Product::class, - ['getPriceInfo', '__wakeup', 'getCanShowPrice'], + ['getPriceInfo', '__wakeup', 'getCanShowPrice', 'isSalable'], [], '', false @@ -78,9 +94,7 @@ protected function setUp() $this->priceBox = $this->getMock(\Magento\Framework\Pricing\Render\PriceBox::class, [], [], '', false); $this->logger = $this->getMock(\Psr\Log\LoggerInterface::class); - $this->layout->expects($this->any()) - ->method('getBlock') - ->will($this->returnValue($this->priceBox)); + $this->layout->expects($this->any())->method('getBlock')->willReturn($this->priceBox); $cacheState = $this->getMockBuilder(\Magento\Framework\App\Cache\StateInterface::class) ->getMockForAbstractClass(); @@ -93,12 +107,9 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $urlBuilder = $this->getMockBuilder(\Magento\Framework\UrlInterface::class) - ->getMockForAbstractClass(); - - $store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) - ->getMockForAbstractClass(); + $urlBuilder = $this->getMockBuilder(\Magento\Framework\UrlInterface::class)->getMockForAbstractClass(); + $store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)->getMockForAbstractClass(); $storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) ->setMethods(['getStore', 'getCode']) ->getMockForAbstractClass(); @@ -144,6 +155,11 @@ protected function setUp() ->will($this->returnValue(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE)); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->salableResolverMock = $this->getMockBuilder(SalableResolverInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->minimalPriceCalculator = $this->getMockForAbstractClass(MinimalPriceCalculatorInterface::class); $this->object = $objectManager->getObject( \Magento\Catalog\Pricing\Render\FinalPriceBox::class, [ @@ -151,7 +167,9 @@ protected function setUp() 'saleableItem' => $this->product, 'rendererPool' => $this->rendererPool, 'price' => $this->price, - 'data' => ['zone' => 'test_zone', 'list_category_page' => true] + 'data' => ['zone' => 'test_zone', 'list_category_page' => true], + 'salableResolver' => $this->salableResolverMock, + 'minimalPriceCalculator' => $this->minimalPriceCalculator ] ); } @@ -169,6 +187,8 @@ public function testRenderMsrpDisabled() ->with($this->equalTo($this->product)) ->will($this->returnValue(false)); + $this->salableResolverMock->expects($this->once())->method('isSalable')->with($this->product)->willReturn(true); + $result = $this->object->toHtml(); //assert price wrapper @@ -177,6 +197,18 @@ public function testRenderMsrpDisabled() $this->assertRegExp('/[final_price]/', $result); } + public function testNotSalableItem() + { + $this->salableResolverMock + ->expects($this->once()) + ->method('isSalable') + ->with($this->product) + ->willReturn(false); + $result = $this->object->toHtml(); + + $this->assertEmpty($result); + } + public function testRenderMsrpEnabled() { $priceType = $this->getMock(\Magento\Msrp\Pricing\Price\MsrpPrice::class, [], [], '', false); @@ -211,6 +243,8 @@ public function testRenderMsrpEnabled() ->with('msrp_price', $this->product, $arguments) ->will($this->returnValue($priceBoxRender)); + $this->salableResolverMock->expects($this->once())->method('isSalable')->with($this->product)->willReturn(true); + $result = $this->object->toHtml(); //assert price wrapper @@ -230,6 +264,8 @@ public function testRenderMsrpNotRegisteredException() ->with($this->equalTo('msrp_price')) ->will($this->throwException(new \InvalidArgumentException())); + $this->salableResolverMock->expects($this->once())->method('isSalable')->with($this->product)->willReturn(true); + $result = $this->object->toHtml(); //assert price wrapper @@ -240,11 +276,17 @@ public function testRenderMsrpNotRegisteredException() public function testRenderAmountMinimal() { - $priceType = $this->getMock(\Magento\Catalog\Pricing\Price\FinalPrice::class, [], [], '', false); - $amount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); $priceId = 'price_id'; $html = 'html'; + $this->object->setData('price_id', $priceId); + $this->product->expects($this->never())->method('getId'); + + $amount = $this->getMockForAbstractClass(AmountInterface::class); + + $this->minimalPriceCalculator->expects($this->once())->method('getAmount') + ->with($this->product) + ->willReturn($amount); $arguments = [ 'zone' => 'test_zone', @@ -255,24 +297,15 @@ public function testRenderAmountMinimal() 'skip_adjustments' => true, ]; - $amountRender = $this->getMock(\Magento\Framework\Pricing\Render\Amount::class, ['toHtml'], [], '', false); + $amountRender = $this->getMock(Amount::class, ['toHtml'], [], '', false); $amountRender->expects($this->once()) ->method('toHtml') - ->will($this->returnValue($html)); - - $this->priceInfo->expects($this->once()) - ->method('getPrice') - ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) - ->will($this->returnValue($priceType)); - - $priceType->expects($this->once()) - ->method('getMinimalPrice') - ->will($this->returnValue($amount)); + ->willReturn($html); $this->rendererPool->expects($this->once()) ->method('createAmountRender') ->with($amount, $this->product, $this->price, $arguments) - ->will($this->returnValue($amountRender)); + ->willReturn($amountRender); $this->assertEquals($html, $this->object->renderAmountMinimal()); } @@ -327,36 +360,29 @@ public function hasSpecialPriceProvider() public function testShowMinimalPrice() { - $finalPrice = 10.0; $minimalPrice = 5.0; - $displayMininmalPrice = 2.0; - - $this->object->setDisplayMinimalPrice($displayMininmalPrice); - - $finalPriceType = $this->getMock(\Magento\Catalog\Pricing\Price\FinalPrice::class, [], [], '', false); + $finalPrice = 10.0; + $displayMininmalPrice = true; - $finalPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); - $minimalPriceAmount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); + $this->minimalPriceCalculator->expects($this->once())->method('getValue')->with($this->product) + ->willReturn($minimalPrice); + $finalPriceAmount = $this->getMockForAbstractClass(AmountInterface::class); $finalPriceAmount->expects($this->once()) ->method('getValue') ->will($this->returnValue($finalPrice)); - $minimalPriceAmount->expects($this->once()) - ->method('getValue') - ->will($this->returnValue($minimalPrice)); - $finalPriceType->expects($this->at(0)) + $finalPriceType = $this->getMock(FinalPrice::class, [], [], '', false); + $finalPriceType->expects($this->once()) ->method('getAmount') ->will($this->returnValue($finalPriceAmount)); - $finalPriceType->expects($this->at(1)) - ->method('getMinimalPrice') - ->will($this->returnValue($minimalPriceAmount)); $this->priceInfo->expects($this->once()) ->method('getPrice') - ->with(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE) - ->will($this->returnValue($finalPriceType)); + ->with(FinalPrice::PRICE_CODE) + ->willReturn($finalPriceType); + $this->object->setDisplayMinimalPrice($displayMininmalPrice); $this->assertTrue($this->object->showMinimalPrice()); } diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/PriceBoxTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/PriceBoxTest.php index 1e8b930a0c491..1b7cc7926da62 100644 --- a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/PriceBoxTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/PriceBoxTest.php @@ -1,6 +1,6 @@ assertArrayHasKey($groupCode, $this->getModel()->modifyMeta($meta)); } + + public function testModifyMetaWithCaching() + { + $this->arrayManagerMock->expects($this->exactly(2)) + ->method('findPath') + ->willReturn(true); + $cacheManager = $this->getMockBuilder(CacheInterface::class) + ->getMockForAbstractClass(); + $cacheManager->expects($this->once()) + ->method('load') + ->with(Categories::CATEGORY_TREE_ID . '_'); + $cacheManager->expects($this->once()) + ->method('save'); + + $modifier = $this->createModel(); + $cacheContextProperty = new \ReflectionProperty( + Categories::class, + 'cacheManager' + ); + $cacheContextProperty->setAccessible(true); + $cacheContextProperty->setValue($modifier, $cacheManager); + + $groupCode = 'test_group_code'; + $meta = [ + $groupCode => [ + 'children' => [ + 'category_ids' => [ + 'sortOrder' => 10, + ], + ], + ], + ]; + $modifier->modifyMeta($meta); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php index c2b3de0c24cb0..5b663363921cb 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CustomOptionsTest.php @@ -1,6 +1,6 @@ [ - \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\CustomOptions::DATA_SOURCE_DEFAULT => [ + CustomOptions::DATA_SOURCE_DEFAULT => [ 'title' => 'original' ] ] ]; $options = [ - $this->getProductOptionMock(['title' => 'option1']), + $this->getProductOptionMock(['title' => 'option1', 'store_title' => 'Option Store Title']), $this->getProductOptionMock( - ['title' => 'option2'], + ['title' => 'option2', 'store_title' => null], [ - $this->getProductOptionMock(['title' => 'value1']), - $this->getProductOptionMock(['title' => 'value2']) + $this->getProductOptionMock(['title' => 'value1', 'store_title' => 'Option Value Store Title']), + $this->getProductOptionMock(['title' => 'value2', 'store_title' => null]) ] ) ]; $resultData = [ $productId => [ - \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\CustomOptions::DATA_SOURCE_DEFAULT => [ - 'title' => 'original', - \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\CustomOptions::FIELD_ENABLE => 1, - \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\CustomOptions::GRID_OPTIONS_NAME => [ - ['title' => 'option1'], + CustomOptions::DATA_SOURCE_DEFAULT => [ + CustomOptions::FIELD_TITLE_NAME => 'original', + CustomOptions::FIELD_ENABLE => 1, + CustomOptions::GRID_OPTIONS_NAME => [ [ - 'title' => 'option2', + CustomOptions::FIELD_TITLE_NAME => 'option1', + CustomOptions::FIELD_STORE_TITLE_NAME => 'Option Store Title', + CustomOptions::FIELD_IS_USE_DEFAULT => false + ], [ + CustomOptions::FIELD_TITLE_NAME => 'option2', + CustomOptions::FIELD_STORE_TITLE_NAME => null, + CustomOptions::FIELD_IS_USE_DEFAULT => true, CustomOptions::GRID_TYPE_SELECT_NAME => [ - ['title' => 'value1'], - ['title' => 'value2'] + [ + CustomOptions::FIELD_TITLE_NAME => 'value1', + CustomOptions::FIELD_STORE_TITLE_NAME => 'Option Value Store Title', + CustomOptions::FIELD_IS_USE_DEFAULT => false + ], [ + CustomOptions::FIELD_TITLE_NAME => 'value2', + CustomOptions::FIELD_STORE_TITLE_NAME => null, + CustomOptions::FIELD_IS_USE_DEFAULT => true + ] ] ] ] @@ -154,13 +166,13 @@ public function testModifyMeta() */ protected function getProductOptionMock(array $data, array $values = []) { + /** @var ProductOption|\PHPUnit_Framework_MockObject_MockObject $productOptionMock */ $productOptionMock = $this->getMockBuilder(ProductOption::class) ->disableOriginalConstructor() + ->setMethods(['getValues']) ->getMock(); - $productOptionMock->expects($this->any()) - ->method('getData') - ->willReturn($data); + $productOptionMock->setData($data); $productOptionMock->expects($this->any()) ->method('getValues') ->willReturn($values); diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php index 2deb4800bd023..c92424fbebbf4 100755 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/EavTest.php @@ -1,6 +1,6 @@ assertSame($this->getSampleData(), $this->getModel()->modifyData($this->getSampleData())); + $this->productMock->expects($this->once())->method('getId')->willReturn(2051); + $actualResult = $this->getModel()->modifyData($this->getSampleData()); + $this->assertSame("", $actualResult[2051]['product']['media_gallery']['images'][0]['label']); } public function testModifyMeta() @@ -40,4 +42,24 @@ public function testModifyMeta() $this->assertSame([], $this->getModel()->modifyMeta($meta)); } + + /** + * {@inheritdoc} + */ + protected function getSampleData() + { + return [ + 2051 => [ + 'product' => [ + 'media_gallery' => [ + 'images' => [ + [ + 'label' => null + ] + ] + ] + ] + ] + ]; + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/RelatedTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/RelatedTest.php index b0b2365c4f151..8bfcc0edd196e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/RelatedTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/RelatedTest.php @@ -1,6 +1,6 @@ productPriceOptions = $this->getMock(ProductPriceOptionsInterface::class); + $this->arrayManager = $this->getMock(ArrayManager::class, [], [], '', false); + + $this->tierPrice = (new ObjectManager($this))->getObject(TierPrice::class, [ + 'productPriceOptions' => $this->productPriceOptions, + 'arrayManager' => $this->arrayManager, + ]); + } + + /** + * Test modifyData. + */ + public function testModifyData() + { + $data = [1, 2]; + $this->assertEquals($data, $this->tierPrice->modifyData($data)); + } + + /** + * Test modifyMeta. + */ + public function testModifyMeta() + { + $meta = [1, 2]; + $tierPricePath = 'tier_price'; + $priceWrapperPath = 'tier_price/some-wrapper'; + $pricePath = $priceWrapperPath . '/price'; + $priceMeta = [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'visible' => true, + 'validation' => ['validate-number' => true], + ], + ], + ], + ]; + + $this->productPriceOptions->expects($this->once())->method('toOptionArray')->willReturn([ + [ + 'value' => ProductPriceOptionsInterface::VALUE_FIXED, + 'label' => 'label1', + ], + ]); + + $this->productPriceOptions->expects($this->once())->method('toOptionArray')->willReturn([ + [ + 'value' => ProductPriceOptionsInterface::VALUE_FIXED, + 'label' => 'label1', + ], + ]); + + $this->arrayManager + ->expects($this->exactly(2)) + ->method('findPath') + ->willReturnMap([ + [ + ProductAttributeInterface::CODE_TIER_PRICE, + $meta, + null, + 'children', + ArrayManager::DEFAULT_PATH_DELIMITER, + $tierPricePath + ], + [ + ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE, + $meta, + $tierPricePath, + null, + ArrayManager::DEFAULT_PATH_DELIMITER, + $pricePath + ], + ]); + $this->arrayManager + ->expects($this->once()) + ->method('get') + ->with($pricePath, $meta) + ->willReturn($priceMeta); + $this->arrayManager + ->expects($this->once()) + ->method('remove') + ->with($pricePath, $meta) + ->willReturn($meta); + $this->arrayManager + ->expects($this->once()) + ->method('slicePath') + ->with($pricePath, 0, -1) + ->willReturn($priceWrapperPath); + $this->arrayManager + ->expects($this->once()) + ->method('merge') + ->with($priceWrapperPath, $meta, $this->isType('array')) + ->willReturnArgument(2); + + $modifiedMeta = $this->tierPrice->modifyMeta($meta); + $children = $modifiedMeta['price_value']['children']; + + $this->assertNotEmpty($children[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_VALUE_TYPE]); + $this->assertNotEmpty($children[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PERCENTAGE_VALUE]); + $this->assertEquals($priceMeta, $children[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE]); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php index deaadb0f12f95..a6b2b82fe6bcc 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/WebsitesTest.php @@ -1,6 +1,6 @@ locator = $locator; $this->storeManager = $storeManager; @@ -113,6 +121,8 @@ public function __construct( $this->directoryHelper = $directoryHelper; $this->arrayManager = $arrayManager; $this->scopeName = $scopeName; + $this->customerGroupSource = $customerGroupSource + ?: ObjectManager::getInstance()->get(GroupSourceInterface::class); } /** @@ -174,7 +184,7 @@ protected function preparePriceFields($fieldCode) * * @return $this */ - protected function customizeTierPrice() + private function customizeTierPrice() { $tierPricePath = $this->arrayManager->findPath( ProductAttributeInterface::CODE_TIER_PRICE, @@ -209,28 +219,13 @@ protected function customizeTierPrice() * * @return array */ - protected function getCustomerGroups() + private function getCustomerGroups() { if (!$this->moduleManager->isEnabled('Magento_Customer')) { return []; } - $customerGroups = [ - [ - 'label' => __('ALL GROUPS'), - 'value' => GroupInterface::CUST_GROUP_ALL, - ] - ]; - - /** @var GroupInterface[] $groups */ - $groups = $this->groupRepository->getList($this->searchCriteriaBuilder->create()); - foreach ($groups->getItems() as $group) { - $customerGroups[] = [ - 'label' => $group->getCode(), - 'value' => $group->getId(), - ]; - } - return $customerGroups; + return $this->customerGroupSource->toOptionArray(); } /** @@ -238,7 +233,7 @@ protected function getCustomerGroups() * * @return bool */ - protected function isScopeGlobal() + private function isScopeGlobal() { return $this->locator->getProduct() ->getResource() @@ -251,7 +246,7 @@ protected function isScopeGlobal() * * @return array */ - protected function getWebsites() + private function getWebsites() { $websites = [ [ @@ -292,7 +287,7 @@ protected function getWebsites() * * @return int */ - protected function getDefaultCustomerGroup() + private function getDefaultCustomerGroup() { return $this->groupManagement->getAllCustomersGroup()->getId(); } @@ -316,7 +311,7 @@ public function getDefaultWebsite() * * @return bool */ - protected function isShowWebsiteColumn() + private function isShowWebsiteColumn() { if ($this->isScopeGlobal() || $this->storeManager->isSingleStoreMode()) { return false; @@ -329,7 +324,7 @@ protected function isShowWebsiteColumn() * * @return bool */ - protected function isMultiWebsites() + private function isMultiWebsites() { return !$this->storeManager->isSingleStoreMode(); } @@ -339,7 +334,7 @@ protected function isMultiWebsites() * * @return bool */ - protected function isAllowChangeWebsite() + private function isAllowChangeWebsite() { if (!$this->isShowWebsiteColumn() || $this->locator->getProduct()->getStoreId()) { return false; @@ -352,7 +347,7 @@ protected function isAllowChangeWebsite() * * @return $this */ - protected function addAdvancedPriceLink() + private function addAdvancedPriceLink() { $pricePath = $this->arrayManager->findPath( ProductAttributeInterface::CODE_PRICE, @@ -405,13 +400,14 @@ protected function addAdvancedPriceLink() * @return array * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - protected function getTierPriceStructure($tierPricePath) + private function getTierPriceStructure($tierPricePath) { return [ 'arguments' => [ 'data' => [ 'config' => [ 'componentType' => 'dynamicRows', + 'component' => 'Magento_Catalog/js/components/dynamic-rows-tier-price', 'label' => __('Customer Group Price'), 'renderDefaultRecord' => false, 'recordTemplate' => 'record', @@ -420,6 +416,7 @@ protected function getTierPriceStructure($tierPricePath) 'enabled' => false, ], 'disabled' => false, + 'required' => false, 'sortOrder' => $this->arrayManager->get($tierPricePath . '/arguments/data/config/sortOrder', $this->meta), ], @@ -452,6 +449,7 @@ protected function getTierPriceStructure($tierPricePath) 'value' => $this->getDefaultWebsite(), 'visible' => $this->isMultiWebsites(), 'disabled' => ($this->isShowWebsiteColumn() && !$this->isAllowChangeWebsite()), + 'sortOrder' => 10, ], ], ], @@ -467,6 +465,7 @@ protected function getTierPriceStructure($tierPricePath) 'label' => __('Customer Group'), 'options' => $this->getCustomerGroups(), 'value' => $this->getDefaultCustomerGroup(), + 'sortOrder' => 20, ], ], ], @@ -480,6 +479,7 @@ protected function getTierPriceStructure($tierPricePath) 'dataType' => Number::NAME, 'label' => __('Quantity'), 'dataScope' => 'price_qty', + 'sortOrder' => 30, 'validation' => [ 'required-entry' => true, 'validate-greater-than-zero' => true, @@ -502,11 +502,15 @@ protected function getTierPriceStructure($tierPricePath) 'addbefore' => $this->locator->getStore() ->getBaseCurrency() ->getCurrencySymbol(), + 'sortOrder' => 40, 'validation' => [ 'required-entry' => true, 'validate-greater-than-zero' => true, 'validate-number' => true, ], + 'imports' => [ + 'priceValue' => '${ $.provider }:data.product.price', + ], ], ], ], @@ -518,6 +522,7 @@ protected function getTierPriceStructure($tierPricePath) 'componentType' => 'actionDelete', 'dataType' => Text::NAME, 'label' => '', + 'sortOrder' => 50, ], ], ], @@ -533,7 +538,7 @@ protected function getTierPriceStructure($tierPricePath) * * @return $this */ - protected function specialPriceDataToInline() + private function specialPriceDataToInline() { $pathFrom = $this->arrayManager->findPath('special_from_date', $this->meta, null, 'children'); $pathTo = $this->arrayManager->findPath('special_to_date', $this->meta, null, 'children'); @@ -589,7 +594,7 @@ protected function specialPriceDataToInline() * * @return $this */ - protected function customizeAdvancedPricing() + private function customizeAdvancedPricing() { $this->meta['advanced-pricing']['arguments']['data']['config']['opened'] = true; $this->meta['advanced-pricing']['arguments']['data']['config']['collapsible'] = false; @@ -646,9 +651,9 @@ protected function customizeAdvancedPricing() /** * Retrieve store * - * @return \Magento\Store\Model\Store + * @return \Magento\Store\Api\Data\StoreInterface */ - protected function getStore() + private function getStore() { return $this->locator->getStore(); } diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php index 9ca34ff764dcd..d5aab5340f771 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AttributeSet.php @@ -1,6 +1,6 @@ locator = $locator; $this->categoryCollectionFactory = $categoryCollectionFactory; $this->dbHelper = $dbHelper; $this->urlBuilder = $urlBuilder; $this->arrayManager = $arrayManager; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); + } + + /** + * Retrieve cache interface + * + * @return CacheInterface + * @deprecated + */ + private function getCacheManager() + { + if (!$this->cacheManager) { + $this->cacheManager = ObjectManager::getInstance() + ->get(CacheInterface::class); + } + return $this->cacheManager; } /** @@ -254,8 +293,9 @@ protected function customizeCategoriesField(array $meta) */ protected function getCategoriesTree($filter = null) { - if (isset($this->categoriesTrees[$filter])) { - return $this->categoriesTrees[$filter]; + $categoryTree = $this->getCacheManager()->load(self::CATEGORY_TREE_ID . '_' . $filter); + if ($categoryTree) { + return $this->serializer->unserialize($categoryTree); } $storeId = $this->locator->getStore()->getId(); @@ -307,9 +347,16 @@ protected function getCategoriesTree($filter = null) $categoryById[$category->getId()]['label'] = $category->getName(); $categoryById[$category->getParentId()]['optgroup'][] = &$categoryById[$category->getId()]; } + + $this->getCacheManager()->save( + $this->serializer->serialize($categoryById[CategoryModel::TREE_ROOT_ID]['optgroup']), + self::CATEGORY_TREE_ID . '_' . $filter, + [ + \Magento\Catalog\Model\Category::CACHE_TAG, + \Magento\Framework\App\Cache\Type\Block::CACHE_TAG + ] + ); - $this->categoriesTrees[$filter] = $categoryById[CategoryModel::TREE_ROOT_ID]['optgroup']; - - return $this->categoriesTrees[$filter]; + return $categoryById[CategoryModel::TREE_ROOT_ID]['optgroup']; } } diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php index 20a56a92acee3..9041dcc0380b6 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php @@ -1,6 +1,6 @@ $option) { - $options[$index] = $this->formatPriceByPath(static::FIELD_PRICE_NAME, $option->getData()); + $optionData = $option->getData(); + $optionData[static::FIELD_IS_USE_DEFAULT] = !$option->getData(static::FIELD_STORE_TITLE_NAME); + $options[$index] = $this->formatPriceByPath(static::FIELD_PRICE_NAME, $optionData); $values = $option->getValues() ?: []; + foreach ($values as $value) { + $value->setData(static::FIELD_IS_USE_DEFAULT, !$value->getData(static::FIELD_STORE_TITLE_NAME)); + } /** @var \Magento\Catalog\Model\Product\Option $value */ foreach ($values as $value) { $options[$index][static::GRID_TYPE_SELECT_NAME][] = $this->formatPriceByPath( @@ -362,7 +369,7 @@ protected function getOptionsGridConfig($sortOrder) 'collapsibleHeader' => true, 'sortOrder' => $sortOrder, 'dataProvider' => static::CUSTOM_OPTIONS_LISTING, - 'links' => ['insertData' => '${ $.provider }:${ $.dataProvider }'], + 'imports' => ['insertData' => '${ $.provider }:${ $.dataProvider }'], ], ], ], @@ -478,8 +485,7 @@ protected function getImportOptionsModalConfig() 'ns' => static::CUSTOM_OPTIONS_LISTING, 'render_url' => $this->urlBuilder->getUrl('mui/index/render'), 'realTimeLink' => true, - 'behaviourType' => 'edit', - 'externalFilterMode' => true, + 'externalFilterMode' => false, 'currentProductId' => $this->locator->getProduct()->getId(), 'dataLinks' => [ 'imports' => false, @@ -530,7 +536,8 @@ protected function getCommonContainerConfig($sortOrder) 'component' => 'Magento_Catalog/component/static-type-input', 'valueUpdate' => 'input', 'imports' => [ - 'optionId' => '${ $.provider }:${ $.parentScope }.option_id' + 'optionId' => '${ $.provider }:${ $.parentScope }.option_id', + 'isUseDefault' => '${ $.provider }:${ $.parentScope }.is_use_default' ] ], ], @@ -605,6 +612,7 @@ protected function getSelectTypeGridConfig($sortOrder) 'imports' => [ 'optionId' => '${ $.provider }:${ $.parentScope }.option_id', 'optionTypeId' => '${ $.provider }:${ $.parentScope }.option_type_id', + 'isUseDefault' => '${ $.provider }:${ $.parentScope }.is_use_default' ], 'service' => [ 'template' => 'Magento_Catalog/form/element/helper/custom-option-type-service', @@ -1110,7 +1118,7 @@ private function getLocaleCurrency() } return $this->localeCurrency; } - + /** * Format price according to the locale of the currency * diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php index 1419c17e11b29..687f6349146c2 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php @@ -1,6 +1,6 @@ false, - 'add_widgets' => false + 'add_widgets' => false, + 'add_directives' => true, + 'use_container' => true, + 'container_class' => 'hor-scroll', ]; return $meta; diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php index 7b54a508b8168..8c4dac63e21eb 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/General.php @@ -1,6 +1,6 @@ arrayManager->replace( $path, $data, - $this->formatNumber($this->arrayManager->get($path, $data)) + $this->formatWeight($this->arrayManager->get($path, $data)) ); } @@ -105,7 +98,7 @@ protected function customizeAdvancedPriceFormat(array $data) $value[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE] = $this->formatPrice($value[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE]); $value[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE_QTY] = - $this->formatNumber((int)$value[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE_QTY]); + (int)$value[ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE_QTY]; } } @@ -322,17 +315,6 @@ protected function customizeNameListeners(array $meta) $importsConfig = [ 'mask' => $this->locator->getStore()->getConfig('catalog/fields_masks/' . $listener), 'component' => 'Magento_Catalog/js/components/import-handler', - 'imports' => [ - 'handleNameChanges' => '${$.provider}:data.product.name', - 'handleDescriptionChanges' => '${$.provider}:data.product.description', - 'handleSkuChanges' => '${$.provider}:data.product.sku', - 'handleColorChanges' => '${$.provider}:data.product.color', - 'handleCountryChanges' => '${$.provider}:data.product.country_of_manufacture', - 'handleGenderChanges' => '${$.provider}:data.product.gender', - 'handleMaterialChanges' => '${$.provider}:data.product.material', - 'handleShortDescriptionChanges' => '${$.provider}:data.product.short_description', - 'handleSizeChanges' => '${$.provider}:data.product.size' - ], 'allowImport' => !$this->locator->getProduct()->getId(), ]; @@ -373,28 +355,12 @@ protected function customizeNameListeners(array $meta) private function getLocaleCurrency() { if ($this->localeCurrency === null) { - $this->localeCurrency = \Magento\Framework\App\ObjectManager::getInstance()->get(CurrencyInterface::class); + $this->localeCurrency = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Locale\CurrencyInterface::class); } return $this->localeCurrency; } - /** - * The getter function to get the store manager for real application code - * - * @return \Magento\Store\Model\StoreManagerInterface - * - * @deprecated - */ - private function getStoreManager() - { - if ($this->storeManager === null) { - $this->storeManager = - \Magento\Framework\App\ObjectManager::getInstance()->get(StoreManagerInterface::class); - } - return $this->storeManager; - } - - /** * Format price according to the locale of the currency * @@ -407,7 +373,7 @@ protected function formatPrice($value) return null; } - $store = $this->getStoreManager()->getStore(); + $store = $this->locator->getStore(); $currency = $this->getLocaleCurrency()->getCurrency($store->getBaseCurrencyCode()); $value = $currency->toCurrency($value, ['display' => \Magento\Framework\Currency::NO_SYMBOL]); @@ -428,7 +394,7 @@ protected function formatNumber($value) $value = (float)$value; $precision = strlen(substr(strrchr($value, "."), 1)); - $store = $this->getStoreManager()->getStore(); + $store = $this->locator->getStore(); $currency = $this->getLocaleCurrency()->getCurrency($store->getBaseCurrencyCode()); $value = $currency->toCurrency($value, ['display' => \Magento\Framework\Currency::NO_SYMBOL, 'precision' => $precision]); diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Images.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Images.php index 810a06df4a42f..e7b3e86083a8e 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Images.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Images.php @@ -1,6 +1,6 @@ locator->getProduct(); + $modelId = $product->getId(); + if ( + isset($data[$modelId][self::DATA_SOURCE_DEFAULT]['media_gallery']) + && !empty($data[$modelId][self::DATA_SOURCE_DEFAULT]['media_gallery']) + && !empty($data[$modelId][self::DATA_SOURCE_DEFAULT]['media_gallery']['images']) + ) { + foreach ($data[$modelId][self::DATA_SOURCE_DEFAULT]['media_gallery']['images'] as $index => $image) { + if (!isset($image['label'])) { + $data[$modelId][self::DATA_SOURCE_DEFAULT]['media_gallery']['images'][$index]['label'] = ""; + } + } + }; + return $data; } } diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php index 9c488cbebe11a..a9f14444a6b09 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Related.php @@ -1,6 +1,6 @@ productPriceOptions = $productPriceOptions; + $this->arrayManager = $arrayManager; + } + + /** + * {@inheritdoc} + */ + public function modifyData(array $data) + { + return $data; + } + + /** + * {@inheritdoc} + */ + public function modifyMeta(array $meta) + { + $tierPricePath = $this->arrayManager->findPath( + ProductAttributeInterface::CODE_TIER_PRICE, + $meta, + null, + 'children' + ); + if ($tierPricePath) { + $pricePath = $this->arrayManager->findPath( + ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE, + $meta, + $tierPricePath + ); + + if ($pricePath) { + $priceMeta = $this->arrayManager->get($pricePath, $meta); + $updatedStructure = $this->getUpdatedTierPriceStructure($priceMeta); + $meta = $this->arrayManager->remove($pricePath, $meta); + $meta = $this->arrayManager->merge( + $this->arrayManager->slicePath($pricePath, 0, -1), + $meta, + $updatedStructure + ); + } + } + return $meta; + } + + /** + * Get updated tier price structure. + * + * @param array $priceMeta + * @return array + */ + private function getUpdatedTierPriceStructure(array $priceMeta) + { + $priceTypeOptions = $this->productPriceOptions->toOptionArray(); + $firstOption = $priceTypeOptions ? current($priceTypeOptions) : null; + + $priceMeta['arguments']['data']['config']['visible'] = $firstOption + && $firstOption['value'] == ProductPriceOptionsInterface::VALUE_FIXED; + $priceMeta['arguments']['data']['config']['validation'] = [ + 'validate-number' => true, + ]; + return [ + 'price_value' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Container::NAME, + 'formElement' => Container::NAME, + 'dataType' => Price::NAME, + 'component' => 'Magento_Ui/js/form/components/group', + 'label' => __('Price'), + 'enableLabel' => true, + 'dataScope' => '', + 'additionalClasses' => 'control-grouped', + 'sortOrder' => isset($priceMeta['arguments']['data']['config']['sortOrder']) + ? $priceMeta['arguments']['data']['config']['sortOrder'] : 40, + ], + ], + ], + 'children' => [ + ProductAttributeInterface::CODE_TIER_PRICE_FIELD_VALUE_TYPE => [ + 'arguments' => [ + 'data' => [ + 'options' => $priceTypeOptions, + 'config' => [ + 'componentType' => Field::NAME, + 'formElement' => Select::NAME, + 'dataType' => 'text', + 'component' => 'Magento_Catalog/js/tier-price/value-type-select', + 'prices' => [ + ProductPriceOptionsInterface::VALUE_FIXED => '${ $.parentName }.' + . ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE, + ProductPriceOptionsInterface::VALUE_PERCENT => '${ $.parentName }.' + . ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PERCENTAGE_VALUE, + ], + ], + ], + ], + ], + ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE => $priceMeta, + ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PERCENTAGE_VALUE => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Field::NAME, + 'formElement' => Input::NAME, + 'dataType' => Price::NAME, + 'addbefore' => '%', + 'validation' => [ + 'validate-number' => true, + 'less-than-equals-to' => 100 + ], + 'visible' => $firstOption + && $firstOption['value'] == ProductPriceOptionsInterface::VALUE_PERCENT, + ], + ], + ], + ], + 'price_calc' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'componentType' => Container::NAME, + 'component' => 'Magento_Catalog/js/tier-price/percentage-processor', + 'visible' => false + ], + ], + ] + ] + ], + ], + ]; + } +} diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php index b8f13d899be65..6329c338e7c8d 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Websites.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml index 9993d4657533a..304739b957220 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/di.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ @@ -73,7 +73,6 @@ - @@ -143,6 +142,10 @@ Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Attributes 120 + + Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\TierPrice + 150 + @@ -166,4 +169,14 @@ product_form.product_form + + + Magento\Catalog\Model\Config\Source\Product\Options\TierPrice + + + + + Magento\Catalog\Model\Attribute\ScopeOverriddenValue + + diff --git a/app/code/Magento/Catalog/etc/adminhtml/events.xml b/app/code/Magento/Catalog/etc/adminhtml/events.xml index a77e1e741a4be..034204feff5c9 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/events.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/adminhtml/menu.xml b/app/code/Magento/Catalog/etc/adminhtml/menu.xml index d0f15c930e6d2..ee0d1ec5c4117 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/menu.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/adminhtml/routes.xml b/app/code/Magento/Catalog/etc/adminhtml/routes.xml index 8dac88c2a22cd..5deeddb3bb4bd 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/routes.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/adminhtml/system.xml b/app/code/Magento/Catalog/etc/adminhtml/system.xml index 85949a953fc53..c5a1b3686fbe5 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/system.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/catalog_attributes.xml b/app/code/Magento/Catalog/etc/catalog_attributes.xml index d822d36eabfee..650652aa94555 100644 --- a/app/code/Magento/Catalog/etc/catalog_attributes.xml +++ b/app/code/Magento/Catalog/etc/catalog_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/catalog_attributes.xsd b/app/code/Magento/Catalog/etc/catalog_attributes.xsd index 00384d783eff1..d95d5a17c258e 100644 --- a/app/code/Magento/Catalog/etc/catalog_attributes.xsd +++ b/app/code/Magento/Catalog/etc/catalog_attributes.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/config.xml b/app/code/Magento/Catalog/etc/config.xml index a86b005be2857..4a8a523e0d55c 100644 --- a/app/code/Magento/Catalog/etc/config.xml +++ b/app/code/Magento/Catalog/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/crontab.xml b/app/code/Magento/Catalog/etc/crontab.xml index 2288ed4ebd8a8..d69ac8f319b5e 100644 --- a/app/code/Magento/Catalog/etc/crontab.xml +++ b/app/code/Magento/Catalog/etc/crontab.xml @@ -1,7 +1,7 @@ @@ -13,5 +13,8 @@ 0 0 * * * + + * * * * * + diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 36f072d3b0a15..f5dfee60bb45e 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -1,7 +1,7 @@ @@ -46,6 +46,22 @@ + + + + + + + + + + + + + + + + @@ -470,6 +486,7 @@ + @@ -831,4 +848,50 @@ Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor + + + + + + + + Magento\Catalog\Model\ResourceModel\Product\StatusBaseSelectProcessor + + + + + + + simple + virtual + + + + + + + simple + virtual + bundle + + + + + + + simple + virtual + bundle + + + + + + + simple + virtual + + + + diff --git a/app/code/Magento/Catalog/etc/eav_attributes.xml b/app/code/Magento/Catalog/etc/eav_attributes.xml index c480ea4dd2322..133849a28e048 100644 --- a/app/code/Magento/Catalog/etc/eav_attributes.xml +++ b/app/code/Magento/Catalog/etc/eav_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/events.xml b/app/code/Magento/Catalog/etc/events.xml index 544abf6b9e069..58cbe8d343bd6 100644 --- a/app/code/Magento/Catalog/etc/events.xml +++ b/app/code/Magento/Catalog/etc/events.xml @@ -1,7 +1,7 @@ @@ -51,4 +51,7 @@ + + + diff --git a/app/code/Magento/Catalog/etc/extension_attributes.xml b/app/code/Magento/Catalog/etc/extension_attributes.xml index 976031cb937fe..3136b3df67274 100644 --- a/app/code/Magento/Catalog/etc/extension_attributes.xml +++ b/app/code/Magento/Catalog/etc/extension_attributes.xml @@ -1,7 +1,7 @@ @@ -25,4 +25,10 @@ + + + + + + diff --git a/app/code/Magento/Catalog/etc/frontend/di.xml b/app/code/Magento/Catalog/etc/frontend/di.xml index 9b99bd4a78140..ca1e1e244f49c 100644 --- a/app/code/Magento/Catalog/etc/frontend/di.xml +++ b/app/code/Magento/Catalog/etc/frontend/di.xml @@ -1,7 +1,7 @@ @@ -18,9 +18,6 @@ Magento\Catalog\Model\ResourceModel\Category\Collection\FetchStrategy - - - true diff --git a/app/code/Magento/Catalog/etc/frontend/events.xml b/app/code/Magento/Catalog/etc/frontend/events.xml index 5ef8c72468314..dd225750f73be 100644 --- a/app/code/Magento/Catalog/etc/frontend/events.xml +++ b/app/code/Magento/Catalog/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/frontend/page_types.xml b/app/code/Magento/Catalog/etc/frontend/page_types.xml index 2557d79a1a49b..8f929046afeef 100644 --- a/app/code/Magento/Catalog/etc/frontend/page_types.xml +++ b/app/code/Magento/Catalog/etc/frontend/page_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/frontend/routes.xml b/app/code/Magento/Catalog/etc/frontend/routes.xml index 5adaf604c51d5..d4d52559673d6 100644 --- a/app/code/Magento/Catalog/etc/frontend/routes.xml +++ b/app/code/Magento/Catalog/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Catalog/etc/frontend/sections.xml b/app/code/Magento/Catalog/etc/frontend/sections.xml index 7c36594283640..0bc9c63494b33 100644 --- a/app/code/Magento/Catalog/etc/frontend/sections.xml +++ b/app/code/Magento/Catalog/etc/frontend/sections.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/indexer.xml b/app/code/Magento/Catalog/etc/indexer.xml index 88e6da345c393..5c2ca91e525d9 100644 --- a/app/code/Magento/Catalog/etc/indexer.xml +++ b/app/code/Magento/Catalog/etc/indexer.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/module.xml b/app/code/Magento/Catalog/etc/module.xml index 87e82543fc65b..571176694547a 100644 --- a/app/code/Magento/Catalog/etc/module.xml +++ b/app/code/Magento/Catalog/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Catalog/etc/mview.xml b/app/code/Magento/Catalog/etc/mview.xml index d6614e837dde3..4600bb7fad370 100644 --- a/app/code/Magento/Catalog/etc/mview.xml +++ b/app/code/Magento/Catalog/etc/mview.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/product_options.xml b/app/code/Magento/Catalog/etc/product_options.xml index 48d62d0c2c0ad..43bf4865cb49e 100644 --- a/app/code/Magento/Catalog/etc/product_options.xml +++ b/app/code/Magento/Catalog/etc/product_options.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/product_options.xsd b/app/code/Magento/Catalog/etc/product_options.xsd index a6bcb74ac2894..18b5934c1410f 100644 --- a/app/code/Magento/Catalog/etc/product_options.xsd +++ b/app/code/Magento/Catalog/etc/product_options.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/product_options_merged.xsd b/app/code/Magento/Catalog/etc/product_options_merged.xsd index 2a5951c57787d..7b9e6fa2650ec 100644 --- a/app/code/Magento/Catalog/etc/product_options_merged.xsd +++ b/app/code/Magento/Catalog/etc/product_options_merged.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/product_types.xml b/app/code/Magento/Catalog/etc/product_types.xml index a1516fee38ed5..513f0905b13ce 100644 --- a/app/code/Magento/Catalog/etc/product_types.xml +++ b/app/code/Magento/Catalog/etc/product_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/product_types.xsd b/app/code/Magento/Catalog/etc/product_types.xsd index e0cb33802851e..06999fbeddc7a 100644 --- a/app/code/Magento/Catalog/etc/product_types.xsd +++ b/app/code/Magento/Catalog/etc/product_types.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/product_types_base.xsd b/app/code/Magento/Catalog/etc/product_types_base.xsd index 94d8b87d167e3..eddd7a6845488 100644 --- a/app/code/Magento/Catalog/etc/product_types_base.xsd +++ b/app/code/Magento/Catalog/etc/product_types_base.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/product_types_merged.xsd b/app/code/Magento/Catalog/etc/product_types_merged.xsd index 1a1a9bfd8214c..1b1d92c163989 100644 --- a/app/code/Magento/Catalog/etc/product_types_merged.xsd +++ b/app/code/Magento/Catalog/etc/product_types_merged.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/view.xml b/app/code/Magento/Catalog/etc/view.xml index 756888e3b688f..8c7500d9c1374 100644 --- a/app/code/Magento/Catalog/etc/view.xml +++ b/app/code/Magento/Catalog/etc/view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/webapi.xml b/app/code/Magento/Catalog/etc/webapi.xml index 99670c347a89b..1101a7bc93814 100644 --- a/app/code/Magento/Catalog/etc/webapi.xml +++ b/app/code/Magento/Catalog/etc/webapi.xml @@ -1,7 +1,7 @@ @@ -246,6 +246,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Catalog/etc/webapi_rest/di.xml b/app/code/Magento/Catalog/etc/webapi_rest/di.xml index 8606cd8de1136..67e74dfbfd44e 100644 --- a/app/code/Magento/Catalog/etc/webapi_rest/di.xml +++ b/app/code/Magento/Catalog/etc/webapi_rest/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/webapi_soap/di.xml b/app/code/Magento/Catalog/etc/webapi_soap/di.xml index 9d2f4abfa5b46..cb5273e4aeac5 100644 --- a/app/code/Magento/Catalog/etc/webapi_soap/di.xml +++ b/app/code/Magento/Catalog/etc/webapi_soap/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/etc/widget.xml b/app/code/Magento/Catalog/etc/widget.xml index e9907e5b17700..f54d4af816c09 100644 --- a/app/code/Magento/Catalog/etc/widget.xml +++ b/app/code/Magento/Catalog/etc/widget.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/i18n/en_US.csv b/app/code/Magento/Catalog/i18n/en_US.csv index 2ad2194b36466..94b32f979383d 100644 --- a/app/code/Magento/Catalog/i18n/en_US.csv +++ b/app/code/Magento/Catalog/i18n/en_US.csv @@ -183,7 +183,7 @@ Categories,Categories "Category is not available for requested store.","Category is not available for requested store." "There was a category move error.","There was a category move error." "There was a category move error. %1","There was a category move error. %1" -"You moved the category","You moved the category" +"You moved the category.","You moved the category." "Attribute ""%1"" is required.","Attribute ""%1"" is required." "You saved the category.","You saved the category." "Something went wrong while saving the category.","Something went wrong while saving the category." diff --git a/app/code/Magento/Catalog/registration.php b/app/code/Magento/Catalog/registration.php index 96b9df94d399e..fada27f08c173 100644 --- a/app/code/Magento/Catalog/registration.php +++ b/app/code/Magento/Catalog/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE_ERROR.xml b/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE_ERROR.xml index 2809386e4f94e..30add348f7d2b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE_ERROR.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE_ERROR.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_UPDATE_RESULT.xml b/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_UPDATE_RESULT.xml index a71dd55d3dfc0..ec97c79610237 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_UPDATE_RESULT.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_UPDATE_RESULT.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_add.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_add.xml index 5f376149e96bf..d9c70ae487903 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_add.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_add.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_create.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_create.xml index 0a8b4e2509cd0..02734a674189e 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_create.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_create.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_edit.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_edit.xml index 1f975b4a701a3..799c50dfc4756 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_edit.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_category_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_action_attribute_edit.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_action_attribute_edit.xml index be147a4270879..3a073f75eef12 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_action_attribute_edit.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_action_attribute_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertspricegrid.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertspricegrid.xml index 39b7f82b2e78d..0cd56d138149e 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertspricegrid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertspricegrid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertsstockgrid.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertsstockgrid.xml index 74e558c34cc79..d098da96d3e52 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertsstockgrid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_alertsstockgrid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml index ad6d9f5d4ef94..ddf02a7cdb9c2 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_form.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_form.xml index 59c5d5cff3158..8f4780d34b17d 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml index 5049f5ac8e3f5..a19d29a98720e 100755 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_change_attribute_set.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_change_attribute_set.xml index 82007f774971f..422cf537c3081 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_change_attribute_set.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_change_attribute_set.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssell.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssell.xml index 6f95ce72a20bf..9c1280a2500df 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssell.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssell.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssellgrid.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssellgrid.xml index 808e95a885616..96c66485f2132 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssellgrid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_crosssellgrid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_customoptions.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_customoptions.xml index 064463bd0d613..39781cc8adcf0 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_customoptions.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_customoptions.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_edit.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_edit.xml index d8b0ce7c957e0..3375f5b8233f5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_edit.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_form.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_form.xml index bdcd5da65bbea..194c745e6a65a 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_grid.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_grid.xml index 7343969a40ba4..e214ccad3dc21 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_grid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_index.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_index.xml index 7ee21e218051f..bad6a5d165535 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_index.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml index 0d6dae0c99a87..cb993bc892eac 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_options.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_options.xml index e52d7e7ec1a14..7d88ff2a04384 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_options.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_options.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_optionsimportgrid.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_optionsimportgrid.xml index 699b6084c314a..7f6f62943bbea 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_optionsimportgrid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_optionsimportgrid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_related.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_related.xml index e1f2eb0403580..6b688eeec2084 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_related.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_related.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_relatedgrid.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_relatedgrid.xml index 8d2fb11dc18c1..4a306dd725b91 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_relatedgrid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_relatedgrid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_reload.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_reload.xml index 82007f774971f..422cf537c3081 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_reload.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_reload.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml index 1dc0de6498cb1..bbbc1e21669e1 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml index d61a2c344d666..7caf391119166 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_index.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_index.xml index 23b859d526e10..b25eecbbc2502 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_index.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsell.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsell.xml index f7ec295f154a0..ce0b1521d82e6 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsell.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsell.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsellgrid.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsellgrid.xml index 097649c8c0aa3..83c19659b5135 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsellgrid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_upsellgrid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js b/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js index d2e45cbfb42ee..848d1f1da908c 100644 --- a/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js +++ b/app/code/Magento/Catalog/view/adminhtml/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -17,4 +17,4 @@ var config = { deps: [ 'Magento_Catalog/catalog/product' ] -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml index b1f8197650fd9..eaeed5b12ebaf 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/checkboxes/tree.phtml @@ -1,6 +1,6 @@
    -
    - - - - getStores() as $_store): ?> - - - - - - - getLabelValues() ?> - getStores() as $_store): ?> - - - - -
    getName() ?>
    - getReadOnly()):?> disabled="disabled"/> -
    +
    +
    + + + + getStores() as $_store): ?> + + + + + + + getLabelValues() ?> + getStores() as $_store): ?> + + + + +
    getName() ?>
    + getReadOnly()):?> disabled="disabled"/> +
    +
    diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml index 500126c24b530..1f1dc0925f2c0 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/options.phtml @@ -1,6 +1,6 @@ getStoresSortedBySortOrder(); ?> -
    +
    escapeHtml(__('Manage Options (Values of Your Attribute)')); ?> - -
    +
    +
    diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml index 4379fa062a121..d73e4c6095d9d 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml @@ -1,6 +1,6 @@ escapeJs(__('Please select a node.')) ?>' + }); + return; + } + for (i in currentNode.childNodes) { if (currentNode.childNodes[i].id) { child = editSet.currentNode.childNodes[i]; @@ -253,31 +264,40 @@ addGroup : function() { prompt({ + title: "", content: "", value: "", + validation: true, + validationRules: ['required-entry'], + attributesForm: { + novalidate: 'novalidate', + action: '' + }, + attributesField: { + name: 'name', + 'data-validate': '{required:true}', + maxlength: '255' + }, actions: { confirm: function (group_name) { group_name = group_name.strip(); - if( group_name == '' ) { - self.addGroup(); - } else if( group_name != false && group_name != null && group_name != '' ) { - - if (!editSet.validateGroupName(group_name, 0)) { - return; - } - - var newNode = new Ext.tree.TreeNode({ - text : group_name.escapeHTML(), - cls : 'folder', - allowDrop : true, - allowDrag : true - }); - TreePanels.root.appendChild(newNode); - newNode.addListener('beforemove', editSet.groupBeforeMove); - newNode.addListener('beforeinsert', editSet.groupBeforeInsert); - newNode.addListener('beforeappend', editSet.groupBeforeInsert); - newNode.addListener('click', editSet.register); + + if (!editSet.validateGroupName(group_name, 0)) { + return; } + + var newNode = new Ext.tree.TreeNode({ + text : group_name.escapeHTML(), + cls : 'folder', + allowDrop : true, + allowDrag : true + }); + + TreePanels.root.appendChild(newNode); + newNode.addListener('beforemove', editSet.groupBeforeMove); + newNode.addListener('beforeinsert', editSet.groupBeforeInsert); + newNode.addListener('beforeappend', editSet.groupBeforeInsert); + newNode.addListener('click', editSet.register); } } }); @@ -302,7 +322,7 @@ } for (var i=0; i < TreePanels.root.childNodes.length; i++) { if (TreePanels.root.childNodes[i].text.toLowerCase() == name.toLowerCase() && TreePanels.root.childNodes[i].id != exceptNodeId) { - errorText = ''; + errorText = ''; alert({ content: errorText.replace("/name/",name) }); @@ -313,8 +333,13 @@ }, save : function() { + var block; + if ($('messages')) { $('messages').update(); + } else { + block = jQuery('
    ').attr('id', 'messages'); + jQuery('.page-main-actions').after(block); } TreePanels.rebuildTrees(); if(!jQuery('#set-prop-form').valid()) { diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main/tree/attribute.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main/tree/attribute.phtml index 526d2f98ead9c..2928eff384df6 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main/tree/attribute.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main/tree/attribute.phtml @@ -1,5 +1,5 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/add.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/add.phtml index 536e840249b78..cf40ee6d78af6 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/add.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/add.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/main.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/main.phtml index 3b5748da54823..2cdb9f451a86f 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/main.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/toolbar/main.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml index 0a2fcb84c996c..767b54e0fdadf 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml index 5d35a9e8be152..cb60254d4d8c7 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/wysiwyg/js.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/wysiwyg/js.phtml index 5ffacc462ac83..82d2111b986cd 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/wysiwyg/js.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/wysiwyg/js.phtml @@ -1,6 +1,6 @@ @@ -375,19 +375,6 @@ category URL Key 10 - - ${ $.provider }:data.use_default.url_key - - - - - - - - Use Default - boolean - checkbox - 20 @@ -453,10 +440,9 @@ - admin__field-no-label + admin__field-x-small 170 - - Use Parent Category Settings + Use Parent Category Settings boolean checkbox @@ -464,6 +450,8 @@ 0 0 + Magento_Ui/js/form/element/single-checkbox + toggle @@ -509,20 +497,21 @@ - admin__field-no-label + admin__field-x-small 210 - - Apply Design to Products + Apply Design to Products boolean checkbox - - ns = ${ $.ns }, index = custom_use_parent_settings :checked - 1 0 0 + Magento_Ui/js/form/element/single-checkbox + toggle + + ns = ${ $.ns }, index = custom_use_parent_settings:checked + diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/crosssell_product_listing.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/crosssell_product_listing.xml index 965694d7f94c4..c562cf1096fa3 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/crosssell_product_listing.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/crosssell_product_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml index 9852ad74121c8..28522ca5c2ba2 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/new_category_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/new_category_form.xml index dbe6aa9eb7d91..a0307886770c6 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/new_category_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/new_category_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml index 870304c881627..ab5ab6e288e13 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attribute_add_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attributes_grid.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attributes_grid.xml index 4067cd062de6c..b4b625dbdac92 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attributes_grid.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_attributes_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_custom_options_listing.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_custom_options_listing.xml index 5c7292637129d..2b6db7050d0a9 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_custom_options_listing.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_custom_options_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_form.xml index 2db3d337822b6..b99e01147c00d 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml index ec88952af5033..c2aa0b8c69622 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml @@ -1,7 +1,7 @@ @@ -23,6 +23,9 @@ Magento_Ui/js/grid/provider + + filters.store_id + diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/related_product_listing.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/related_product_listing.xml index 25350158c5297..55863e0a21c0d 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/related_product_listing.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/related_product_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/upsell_product_listing.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/upsell_product_listing.xml index fc03f128f4617..26703ba03c9a0 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/upsell_product_listing.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/upsell_product_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/apply-to-type-switcher.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/apply-to-type-switcher.js index 595638d8ca6ef..13543ade8f726 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/apply-to-type-switcher.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/apply-to-type-switcher.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/base-image-uploader.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/base-image-uploader.js index 9c0d986c7e9f2..4ba2d110ffb34 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/base-image-uploader.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/base-image-uploader.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global alert:true*/ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/assign-products.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/assign-products.js index ad5f52095f36b..1da9c2c379c37 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/assign-products.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/assign-products.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js index 28bc0734ef033..66eb039790f28 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** @@ -75,4 +75,4 @@ define([ categorySubmit(config.url, config.ajax); }); }; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/form.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/form.js index f64111a2f0ef8..9f413832537e2 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/form.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/form.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product-attributes.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product-attributes.js index 937c83c14faa4..78f48b0bafabb 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product-attributes.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product-attributes.js @@ -1,12 +1,13 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ 'jquery', 'underscore', 'uiRegistry', - 'jquery/ui' + 'jquery/ui', + 'mage/translate' ], function ($, _, registry) { 'use strict'; diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product.js index 27fdd1b201885..11a1866284131 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ require([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/attribute/unique-validate.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/attribute/unique-validate.js index c2aa604d11e7a..2af880f4d04c5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/attribute/unique-validate.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/attribute/unique-validate.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js index 28bcd7011ab8f..0f45dda8043d0 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/type-events.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/type-events.js index 55a4599ce85e5..9de0ff75fa843 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/type-events.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/type-events.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/component/file-type-field.js b/app/code/Magento/Catalog/view/adminhtml/web/component/file-type-field.js index 491d765740b0b..bed32eb574695 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/component/file-type-field.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/component/file-type-field.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/component/image-size-field.js b/app/code/Magento/Catalog/view/adminhtml/web/component/image-size-field.js index b330ccfd8c125..13a759e534735 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/component/image-size-field.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/component/image-size-field.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -7,7 +7,8 @@ define([ 'jquery', 'Magento_Ui/js/lib/validation/utils', 'Magento_Ui/js/form/element/abstract', - 'Magento_Ui/js/lib/validation/validator' + 'Magento_Ui/js/lib/validation/validator', + 'mage/translate' ], function ($, utils, Abstract, validator) { 'use strict'; diff --git a/app/code/Magento/Catalog/view/adminhtml/web/component/select-type-grid.js b/app/code/Magento/Catalog/view/adminhtml/web/component/select-type-grid.js index ba5307da4cda1..57d35424268b8 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/component/select-type-grid.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/component/select-type-grid.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-container.js b/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-container.js index 5105271769d71..b3ef035402c3e 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-container.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-container.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-input.js b/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-input.js index 694eb0163467c..d520758d456a5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-input.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-input.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-select.js b/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-select.js index 555024e026a0b..6b61b5e49c97a 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-select.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/component/static-type-select.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/component/text-type-field.js b/app/code/Magento/Catalog/view/adminhtml/web/component/text-type-field.js index d09110f41d3cf..72d97b7aebcd9 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/component/text-type-field.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/component/text-type-field.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/bundle-proxy-button.js b/app/code/Magento/Catalog/view/adminhtml/web/js/bundle-proxy-button.js index 60141a7138008..42543656f210b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/bundle-proxy-button.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/bundle-proxy-button.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js b/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js index 0cb4932a012f3..5453b760e2f31 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ @@ -94,4 +94,4 @@ define([ }); return $.mage.categoryTree; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attribute-set-select.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attribute-set-select.js index 3fa5d6a6790f3..baefa1ae2e4b5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attribute-set-select.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attribute-set-select.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-fieldset.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-fieldset.js index 8b2d64353f72f..1e363ef2a1a0f 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-fieldset.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-fieldset.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-grid-paging.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-grid-paging.js index f698de4a5386f..641dfaf295150 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-grid-paging.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-grid-paging.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-insert-listing.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-insert-listing.js index 5d9234b76d544..10be9f2ffc907 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-insert-listing.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/attributes-insert-listing.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/checkbox.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/checkbox.js index 944ef4f7b4d5f..b371efca26f64 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/checkbox.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/checkbox.js @@ -1,4 +1,4 @@ -/* Copyright © 2016 Magento. All rights reserved. +/* Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-hide-select.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-hide-select.js index fd36504b5a77c..4bf54406e3598 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-hide-select.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-hide-select.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/input.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/input.js index 4dd196da99294..1961bc5fde625 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/input.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/input.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/select.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/select.js index ad6090cdd8e46..2dc21fc11cf55 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/select.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/select.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/strategy.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/strategy.js index 6a31b28df2c05..e8b276c171ca4 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/strategy.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/strategy.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define(function () { diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js index 3c40951499fff..7362acbe63eb2 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/dynamic-rows-import-custom-options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/dynamic-rows-import-custom-options.js index 0dea377e5d84b..d15c7b48dc409 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/dynamic-rows-import-custom-options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/dynamic-rows-import-custom-options.js @@ -1,61 +1,83 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ - 'Magento_Ui/js/dynamic-rows/dynamic-rows', + 'Magento_Ui/js/dynamic-rows/dynamic-rows-grid', + 'underscore', 'mageUtils' -], function (DynamicRows, utils) { +], function (DynamicRows, _, utils) { 'use strict'; + var maxId = 0, + + /** + * Stores max option_id value of the options from recordData once on initialization + * @param {Array} data - array with records data + */ + initMaxId = function (data) { + if (data && data.length) { + maxId = ~~_.max(data, function (record) { + return ~~record['option_id']; + })['option_id']; + } + }; + return DynamicRows.extend({ defaults: { - dataProvider: '', - insertData: [], - listens: { - 'insertData': 'processingInsertData' - } + mappingSettings: { + enabled: false, + distinct: false + }, + update: true, + map: { + 'option_id': 'option_id' + }, + identificationProperty: 'option_id', + identificationDRProperty: 'option_id' }, - /** - * Calls 'initObservable' of parent - * - * @returns {Object} Chainable. - */ - initObservable: function () { - this._super() - .observe([ - 'insertData' - ]); + /** @inheritdoc */ + initialize: function () { + this._super(); + initMaxId(this.recordData()); return this; }, - /** - * Parsed data - * - * @param {Array} data - array with data - * about selected records - */ + /** @inheritdoc */ processingInsertData: function (data) { - if (!data.length) { - return false; - } + var options = [], + currentOption; - data.each(function (options) { - options.options.each(function (option) { - var path = this.dataScope + '.' + this.index + '.' + this.recordIterator, - curOption = utils.copy(option); + if (!data) { + return; + } + data.each(function (item) { + if (!item.options) { + return; + } + item.options.each(function (option) { + currentOption = utils.copy(option); - if (curOption.hasOwnProperty('sort_order')) { - delete curOption['sort_order']; + if (currentOption.hasOwnProperty('sort_order')) { + delete currentOption['sort_order']; } + currentOption['option_id'] = ++maxId; + options.push(currentOption); + }); + }); - this.source.set(path, curOption); - this.addChild(curOption, false); - }, this); + if (!options.length) { + return; + } + this.cacheGridData = options; + options.each(function (opt) { + this.mappingValue(opt); }, this); + + this.insertData([]); }, /** @@ -63,6 +85,27 @@ define([ */ clearDataProvider: function () { this.source.set(this.dataProvider, []); + }, + + /** @inheritdoc */ + processingAddChild: function (ctx, index, prop) { + if (ctx && !_.isNumber(ctx['option_id'])) { + ctx['option_id'] = ++maxId; + } else if (!ctx) { + this.showSpinner(true); + this.addChild(ctx, index, prop); + + return; + } + + this._super(ctx, index, prop); + }, + + /** + * Mutes parent method + */ + updateInsertData: function () { + return false; } }); }); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/dynamic-rows-tier-price.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/dynamic-rows-tier-price.js new file mode 100644 index 0000000000000..c8b66f23abc83 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/dynamic-rows-tier-price.js @@ -0,0 +1,29 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'Magento_Ui/js/dynamic-rows/dynamic-rows' +], function (_, DynamicRows) { + 'use strict'; + + return DynamicRows.extend({ + + /** + * Init header elements + */ + initHeader: function () { + var labels; + + this._super(); + labels = _.clone(this.labels()); + labels = _.sortBy(labels, function (label) { + return label.sortOrder; + }); + + this.labels(labels); + } + }); +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js index fd69874c318e2..a616978f8d369 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/import-handler.js @@ -1,153 +1,81 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ - 'Magento_Ui/js/form/element/textarea' -], function (Textarea) { + 'Magento_Ui/js/form/element/abstract', + 'underscore', + 'uiRegistry' +], function (Abstract, _, registry) { 'use strict'; - return Textarea.extend({ + return Abstract.extend({ defaults: { allowImport: true, autoImportIfEmpty: false, - values: { - 'name': '', - 'description': '', - 'sku': '', - 'color': '', - 'country_of_manufacture': '', - 'gender': '', - 'material': '', - 'short_description': '', - 'size': '' - }, - valueUpdate: 'input', - mask: '' + values: {}, + mask: '', + queryTemplate: 'ns = ${ $.ns }, index = ' }, - /** - * Handle name value changes, if it's allowed - * - * @param {String} newValue - */ - handleNameChanges: function (newValue) { - this.values.name = newValue; - this.updateValue(); - }, - - /** - * Handle description value changes, if it's allowed - * - * @param {String} newValue - */ - handleDescriptionChanges: function (newValue) { - this.values.description = newValue; - this.updateValue(); - }, + /** @inheritdoc */ + initialize: function () { + this._super(); - /** - * Handle sku value changes, if it's allowed - * - * @param {String} newValue - */ - handleSkuChanges: function (newValue) { - if (this.code !== 'sku') { - this.values.sku = newValue; - this.updateValue(); + if (this.allowImport) { + this.setHandlers(); } }, /** - * Handle color value changes, if it's allowed - * - * @param {String} newValue - */ - handleColorChanges: function (newValue) { - this.values.color = newValue; - this.updateValue(); - }, - - /** - * Handle country value changes, if it's allowed - * - * @param {String} newValue + * Split mask placeholder and attach events to placeholder fields. */ - handleCountryChanges: function (newValue) { - this.values.country = newValue; - this.updateValue(); - }, + setHandlers: function () { + var str = this.mask || '', + placeholders; - /** - * Handle gender value changes, if it's allowed - * - * @param {String} newValue - */ - handleGenderChanges: function (newValue) { - this.values.gender = newValue; - this.updateValue(); - }, + placeholders = str.match(/{{(.*?)}}/g); // Get placeholders - /** - * Handle material value changes, if it's allowed - * - * @param {String} newValue - */ - handleMaterialChanges: function (newValue) { - this.values.material = newValue; - this.updateValue(); - }, + _.each(placeholders, function (placeholder) { + placeholder = placeholder.replace(/[{{}}]/g, ''); // Remove curly braces - /** - * Handle short description value changes, if it's allowed - * - * @param {String} newValue - */ - handleShortDescriptionChanges: function (newValue) { - this.values['short_description'] = newValue; - this.updateValue(); + registry.get(this.queryTemplate + placeholder, function (component) { + this.values[placeholder] = component.getPreview(); + component.on('value', this.updateValue.bind(this, placeholder, component)); + component.valueUpdate = 'keyup'; + }.bind(this)); + }, this); }, /** - * Handle size value changes, if it's allowed + * Update field with mask value, if it's allowed. * - * @param {String} newValue + * @param {Object} placeholder + * @param {Object} component */ - handleSizeChanges: function (newValue) { - this.values.size = newValue; - this.updateValue(); - }, + updateValue: function (placeholder, component) { + var string = this.mask || '', + nonEmptyValueFlag = false; - /** - * Update field value, if it's allowed - */ - updateValue: function () { - var str = this.mask, - nonEmptyValueFlag = false, - placeholder, - property, - tmpElement; + if (placeholder) { + this.values[placeholder] = component.getPreview() || ''; + } if (!this.allowImport) { return; } - for (property in this.values) { - if (this.values.hasOwnProperty(property)) { - placeholder = ''; - placeholder = placeholder.concat('{{', property, '}}'); - str = str.replace(placeholder, this.values[property]); - nonEmptyValueFlag = nonEmptyValueFlag || !!this.values[property]; - } - } - // strip tags - tmpElement = document.createElement('div'); - tmpElement.innerHTML = str; - str = tmpElement.textContent || tmpElement.innerText || ''; + _.each(this.values, function (propertyValue, propertyName) { + string = string.replace('{{' + propertyName + '}}', propertyValue); + nonEmptyValueFlag = nonEmptyValueFlag || !!propertyValue; + }); if (nonEmptyValueFlag) { - this.value(str); + string = string.replace(/(<([^>]+)>)/ig, ''); // Remove html tags + this.value(string); + } else { + this.value(''); } }, @@ -171,13 +99,20 @@ define([ * and disallow/allow import value */ userChanges: function () { + + /** + * As userChanges is called before updateValue, + * we forced to get value from component by reference + */ + var actualValue = arguments[1].currentTarget.value; + this._super(); - if (this.value() === '') { + if (actualValue === '') { this.allowImport = true; if (this.autoImportIfEmpty) { - this.updateValue(); + this.updateValue(null, null); } } else { this.allowImport = false; diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/input-handle-required.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/input-handle-required.js index 9d2154656b005..c342e961fa9e2 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/input-handle-required.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/input-handle-required.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/messages.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/messages.js index 78956749be6a9..7e3696ba24bf8 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/messages.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/messages.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/multiselect-handle-required.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/multiselect-handle-required.js index 3e26f693456c4..b7146137c6bb3 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/multiselect-handle-required.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/multiselect-handle-required.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-form.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-form.js index 96d3f0accec5a..360349f8c61e5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-form.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-form.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-insert-form.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-insert-form.js index 4c646b1de8e2f..f3624de9cbd0f 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-insert-form.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-attribute-insert-form.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-category.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-category.js index 8037d1c6ac3f4..7a16067b37291 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-category.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/new-category.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/product-status.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/product-status.js index c02af7c6369b2..3e3c811584973 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/product-status.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/product-status.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-handle-required.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-handle-required.js index dc7b4dee30b1b..08ed325c82a78 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-handle-required.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-handle-required.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-to-checkbox.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-to-checkbox.js index 4232c54e7b617..281ef42a9e533 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-to-checkbox.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/select-to-checkbox.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/url-key-handle-changes.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/url-key-handle-changes.js index 2305a79fa7e73..b12f73c17125a 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/url-key-handle-changes.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/url-key-handle-changes.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/date.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/date.js index 1f1aa3a4a5d4d..ecdb3a66006b7 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/date.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/date.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/fieldset.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/fieldset.js index 2ddd6566cb074..581153832d3a5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/fieldset.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/fieldset.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/input.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/input.js index 950ab4aa4eb34..bd832632f7513 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/input.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/input.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/select.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/select.js index c63e79316b3ec..05453dc19bff8 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/select.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/select.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/strategy.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/strategy.js index 7d1f0557108f5..2e59efeab1b58 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/strategy.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/strategy.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define(function () { diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/textarea.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/textarea.js index 0c0860e1b7102..7446174982a21 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/textarea.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/textarea.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/yesno.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/yesno.js index 5f64db1ee6dd2..9f8a9e43dacc5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/yesno.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/visible-on-option/yesno.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options-type.js b/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options-type.js index e4c65f543eddf..878e8e1429680 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options-type.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options-type.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js index 9de11667b9d56..0611c4fae9233 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/custom-options.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true*/ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/edit-tree.js b/app/code/Magento/Catalog/view/adminhtml/web/js/edit-tree.js index 9d84efd42c7d9..7420595078071 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/edit-tree.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/edit-tree.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/action-delete.js b/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/action-delete.js index d809ecc74fa4b..1ecfddac7abb8 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/action-delete.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/action-delete.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/checkbox.js b/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/checkbox.js index cffa4dff8952b..57d45551d180b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/checkbox.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/checkbox.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/input.js b/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/input.js index 688dc39692dac..84be3a4f8783b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/input.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/form/element/input.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/new-category-dialog.js b/app/code/Magento/Catalog/view/adminhtml/web/js/new-category-dialog.js index 41c29880de8c9..e20d3f3e0c5b1 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/new-category-dialog.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/new-category-dialog.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js index b366f61ba4994..75d768dae7bb6 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/options.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/options.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/product-gallery.js b/app/code/Magento/Catalog/view/adminhtml/web/js/product-gallery.js index eba8ef201eae2..2cfde92d6a762 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/product-gallery.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/product-gallery.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint jquery:true*/ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/product/weight-handler.js b/app/code/Magento/Catalog/view/adminhtml/web/js/product/weight-handler.js index 176cc9bd5c80c..a2ae5b794f601 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/product/weight-handler.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/product/weight-handler.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/percentage-processor.js b/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/percentage-processor.js new file mode 100644 index 0000000000000..85d6f07763b50 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/percentage-processor.js @@ -0,0 +1,73 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'uiElement', + 'underscore', + 'Magento_Ui/js/lib/view/utils/async', + 'Magento_Catalog/js/utils/percentage-price-calculator' +], function (Element, _, $, percentagePriceCalculator) { + 'use strict'; + + return Element.extend({ + defaults: { + priceElem: '${ $.parentName }.price', + selector: 'input', + imports: { + priceValue: '${ $.priceElem }:priceValue' + }, + exports: { + calculatedVal: '${ $.priceElem }:value' + } + }, + + /** + * {@inheritdoc} + */ + initialize: function () { + this._super(); + + _.bindAll(this, 'initPriceListener', 'onInput'); + + $.async({ + component: this.priceElem, + selector: this.selector + }, this.initPriceListener); + + return this; + }, + + /** + * {@inheritdoc} + */ + initObservable: function () { + return this._super() + .observe(['visible']); + }, + + /** + * Handles keyup event on price input. + * + * {@param} HTMLElement elem + */ + initPriceListener: function (elem) { + $(elem).on('keyup.priceCalc', this.onInput); + }, + + /** + * Delegates calculation of the price input value to percentagePriceCalculator. + * + * {@param} object event + */ + onInput: function (event) { + var value = event.currentTarget.value; + + if (value.slice(-1) === '%') { + value = percentagePriceCalculator(this.priceValue, value); + this.set('calculatedVal', value); + } + } + }); +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/value-type-select.js b/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/value-type-select.js new file mode 100644 index 0000000000000..17e5037dc507a --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/tier-price/value-type-select.js @@ -0,0 +1,118 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/element/select', + 'uiRegistry', + 'underscore' +], function (Select, uiRegistry, _) { + 'use strict'; + + return Select.extend({ + defaults: { + prices: {} + }, + + /** + * {@inheritdoc} + */ + initialize: function () { + this._super() + .prepareForm(); + }, + + /** + * {@inheritdoc} + */ + setInitialValue: function () { + this.initialValue = this.getInitialValue(); + + if (this.value.peek() !== this.initialValue) { + this.value(this.initialValue); + } + + this.isUseDefault(this.disabled()); + + return this; + }, + + /** + * {@inheritdoc} + */ + prepareForm: function () { + var elements = this.getElementsByPrices(), + prices = this.prices, + currencyType = _.keys(prices)[0], + select = this; + + uiRegistry.get(elements, function () { + _.each(arguments, function (currentValue) { + if (parseFloat(currentValue.value()) > 0) { + _.each(prices, function (priceValue, priceKey) { + if (priceValue === currentValue.name) { + currencyType = priceKey; + } + }); + } + }); + select.value(currencyType); + select.on('value', select.onUpdate.bind(select)); + select.onUpdate(); + }); + }, + + /** + * @returns {Array} + */ + getElementsByPrices: function () { + var elements = []; + + _.each(this.prices, function (currentValue) { + elements.push(currentValue); + }); + + return elements; + }, + + /** + * Callback that fires when 'value' property is updated + */ + onUpdate: function () { + var value = this.value(), + prices = this.prices, + select = this, + parentDataScopeArr = this.dataScope.split('.'), + parentDataScope, + elements = this.getElementsByPrices(); + + parentDataScopeArr.pop(); + parentDataScope = parentDataScopeArr.join('.'); + + uiRegistry.get(elements, function () { + var sourceData = select.source.get(parentDataScope); + + _.each(arguments, function (currentElement) { + var index; + + _.each(prices, function (priceValue, priceKey) { + if (priceValue === currentElement.name) { + index = priceKey; + } + }); + + if (value === index) { + currentElement.visible(true); + sourceData[currentElement.index] = currentElement.value(); + } else { + currentElement.value(''); + currentElement.visible(false); + delete sourceData[currentElement.index]; + } + }); + select.source.set(parentDataScope, sourceData); + }); + } + }); +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/utils/percentage-price-calculator.js b/app/code/Magento/Catalog/view/adminhtml/web/js/utils/percentage-price-calculator.js new file mode 100644 index 0000000000000..9697cb6bf12cd --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/utils/percentage-price-calculator.js @@ -0,0 +1,45 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define(['Magento_Ui/js/lib/validation/utils'], function (utils) { + 'use strict'; + + /** + * Calculates the price input value when entered percentage value. + * + * @param {String} price + * @param {String} input + * + * @returns {String} + */ + return function (price, input) { + var result, + lastInputSymbol = input.slice(-1), + inputPercent = input.slice(0, -1), + parsedPercent = utils.parseNumber(inputPercent), + parsedPrice = utils.parseNumber(price); + + if (lastInputSymbol !== '%') { + result = input; + } else if ( + input === '%' || + isNaN(parsedPrice) || + parsedPercent != inputPercent || /* eslint eqeqeq:0 */ + isNaN(parsedPercent) || + input === '' + ) { + result = ''; + } else if (parsedPercent > 100) { + result = '0.00'; + } else if (lastInputSymbol === '%') { + result = parsedPrice - parsedPrice * (inputPercent / 100); + result = result.toFixed(2); + } else { + result = input; + } + + return result; + }; +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/attributes/grid/paging.html b/app/code/Magento/Catalog/view/adminhtml/web/template/attributes/grid/paging.html index 6ad88dd64d9e3..bf03ffb1049e7 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/attributes/grid/paging.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/attributes/grid/paging.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/checkbox.html b/app/code/Magento/Catalog/view/adminhtml/web/template/checkbox.html index 9b737a457f3f5..7a2c8e42364df 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/checkbox.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/checkbox.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html index 13445314101b2..687420c9ef156 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html @@ -1,6 +1,6 @@ @@ -13,4 +13,4 @@ } "> - \ No newline at end of file + diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-service.html b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-service.html index 9b1a3936b9f43..ad83bc144615e 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-service.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-service.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-type-service.html b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-type-service.html index a3f7970e7420a..3c3cbbde2ab39 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-type-service.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/helper/custom-option-type-service.html @@ -1,6 +1,6 @@ @@ -12,6 +12,6 @@ name: 'options_use_default[' + $data.optionId + '][values][' + $data.optionTypeId + '][' + $data.index + ']', 'data-form-part': $data.ns " - ko-checked="isUseDefault"> + ko-checked="$data.isUseDefault">
    diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/input.html b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/input.html index 70b1b6033f7f6..560bc90ea6d19 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/input.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/input.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html b/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html index fa8a4fec7cc78..22f7237c6cd4a 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html @@ -1,6 +1,6 @@ @@ -31,5 +31,6 @@
    x +
    diff --git a/app/code/Magento/Catalog/view/base/layout/catalog_product_prices.xml b/app/code/Magento/Catalog/view/base/layout/catalog_product_prices.xml index aeb647660af7c..b47a6a3e69d86 100644 --- a/app/code/Magento/Catalog/view/base/layout/catalog_product_prices.xml +++ b/app/code/Magento/Catalog/view/base/layout/catalog_product_prices.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/base/layout/default.xml b/app/code/Magento/Catalog/view/base/layout/default.xml index 25a23d2be7df4..776dbc4b646ef 100644 --- a/app/code/Magento/Catalog/view/base/layout/default.xml +++ b/app/code/Magento/Catalog/view/base/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/base/layout/empty.xml b/app/code/Magento/Catalog/view/base/layout/empty.xml index 25a23d2be7df4..776dbc4b646ef 100644 --- a/app/code/Magento/Catalog/view/base/layout/empty.xml +++ b/app/code/Magento/Catalog/view/base/layout/empty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/base/templates/js/components.phtml b/app/code/Magento/Catalog/view/base/templates/js/components.phtml index e490a6aa04923..bdcb2e9bf7747 100644 --- a/app/code/Magento/Catalog/view/base/templates/js/components.phtml +++ b/app/code/Magento/Catalog/view/base/templates/js/components.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/default.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/default.phtml index a72cbcf8e8981..01d82db69d2ce 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/default.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/default.phtml @@ -1,6 +1,6 @@ @@ -28,53 +28,6 @@ - - product_list_toolbar diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default.xml index a9cfdf8f834bd..d6788f3d4eed6 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default_without_children.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default_without_children.xml index 7509438df2553..e01b48cc71b11 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default_without_children.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view_type_default_without_children.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_compare_index.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_compare_index.xml index 3e16064e57312..c6f02a8acb155 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_compare_index.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_compare_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_gallery.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_gallery.xml index 837d34157a600..7e39fd35d6cde 100755 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_gallery.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_gallery.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_opengraph.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_opengraph.xml index 6bb8a78949038..661ec52df3dcd 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_opengraph.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_opengraph.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml index 991d9a36d18e0..6e17705f4c464 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml @@ -1,7 +1,7 @@ @@ -101,7 +101,33 @@ + + + gallery-prev-area + + + + + + gallery-next-area + Skip to the end of the images gallery + + + + + + + gallery-prev-area + Skip to the beginning of the images gallery + + + + + + gallery-next-area + + diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_simple.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_simple.xml index bc1959a36cb72..6703d18deac37 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_simple.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_simple.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_virtual.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_virtual.xml index 6155df2f60653..dd93e8064e60c 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_virtual.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view_type_virtual.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/Catalog/view/frontend/layout/checkout_cart_item_renderers.xml index 2ad9ebb874ea2..ee16e638b64cb 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/checkout_cart_item_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/layout/default.xml b/app/code/Magento/Catalog/view/frontend/layout/default.xml index ab424810401c9..f267c2a5ae634 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/default.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Catalog/view/frontend/requirejs-config.js b/app/code/Magento/Catalog/view/frontend/requirejs-config.js index c0d05a322b7cd..a26e53e9620fd 100644 --- a/app/code/Magento/Catalog/view/frontend/requirejs-config.js +++ b/app/code/Magento/Catalog/view/frontend/requirejs-config.js @@ -1,12 +1,11 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ var config = { map: { '*': { - compareItems: 'Magento_Catalog/js/compare', compareList: 'Magento_Catalog/js/list', relatedProducts: 'Magento_Catalog/js/related-products', upsellProducts: 'Magento_Catalog/js/upsell-products', diff --git a/app/code/Magento/Catalog/view/frontend/templates/category/cms.phtml b/app/code/Magento/Catalog/view/frontend/templates/category/cms.phtml index 06d1fc56b6f4b..818456d2272f6 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/category/cms.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/category/cms.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/image_with_borders.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/image_with_borders.phtml index f78631f32a80a..c3280c563fe58 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/image_with_borders.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/image_with_borders.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml index 578a58fb4d48d..bcbd2882e02c2 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml @@ -1,6 +1,6 @@ getProductDefaultQty() * 1 ?>" - title="" class="input-text qty" + title="" + class="input-text qty" data-validate="escapeHtml(json_encode($block->getQuantityValidators())) ?>" /> @@ -58,4 +58,4 @@ } } - \ No newline at end of file + diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/attribute.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/attribute.phtml index eae8197f7231f..cb99796f6617e 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/attribute.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/attribute.phtml @@ -1,6 +1,6 @@ helper('Magento\Catalog\Helper\Output'); - $_product = $block->getProduct() + $_product = $block->getProduct(); ?> getAdditionalData()): ?>
    diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/description.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/description.phtml index 9f7a0ed952c8f..a074e83d77612 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/description.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/description.phtml @@ -1,6 +1,6 @@ escapeHtml($_product->getId())?>]', + priceBoxes = $(dataPriceBoxSelector + dataProductIdSelector); priceBoxes = priceBoxes.filter(function(index, elem){ return !$(elem).find('.price-from').length; diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml index 600902bec5d19..c5e9fc9f6044f 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml @@ -1,6 +1,6 @@ decorateArray($block->getOptions()) ?> +getProduct()->getId() ?> "; - return $javaScript . parent::getAfterElementHtml(); + $elementId = $this->getHtmlId(); + $countryListId = $this->_getSpecificCountryElementId(); + $useDefaultElementId = $countryListId . '_inherit'; + + $elementJavaScript = << +// + +HTML; + + return $elementJavaScript . parent::getAfterElementHtml(); } /** diff --git a/app/code/Magento/Config/Block/System/Config/Form/Fieldset.php b/app/code/Magento/Config/Block/System/Config/Form/Fieldset.php index 6dfa40105cb71..2e867d49c7df4 100644 --- a/app/code/Magento/Config/Block/System/Config/Form/Fieldset.php +++ b/app/code/Magento/Config/Block/System/Config/Form/Fieldset.php @@ -1,6 +1,6 @@ objectManager = $objectManager; + $this->processors = $processors; + } + + /** + * Creates an instance of specified processor. + * + * @param string $processorName The name of processor + * @return ConfigSetProcessorInterface New processor instance + * @throws ConfigurationMismatchException If processor type is not exists in processors array + * or declared class has wrong implementation + */ + public function create($processorName) + { + if (!isset($this->processors[$processorName])) { + throw new ConfigurationMismatchException(__('Class for type "%1" was not declared', $processorName)); + } + + $object = $this->objectManager->create($this->processors[$processorName]); + + if (!$object instanceof ConfigSetProcessorInterface) { + throw new ConfigurationMismatchException( + __('%1 should implement %2', get_class($object), ConfigSetProcessorInterface::class) + ); + } + + return $object; + } +} diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorInterface.php b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorInterface.php new file mode 100644 index 0000000000000..acc9499729da0 --- /dev/null +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorInterface.php @@ -0,0 +1,29 @@ +configFactory = $configFactory; + $this->deploymentConfig = $deploymentConfig; + $this->configPathResolver = $configPathResolver; + } + + /** + * Processes database flow of config:set command. + * Requires installed application. + * + * {@inheritdoc} + */ + public function process($path, $value, $scope, $scopeCode) + { + if (!$this->deploymentConfig->isAvailable()) { + throw new CouldNotSaveException( + __( + 'We can\'t save this option because Magento is not installed. ' + . 'To lock this value, enter the command again using the --%1 option.', + ConfigSetCommand::OPTION_LOCK + ) + ); + } + + if ($this->isLocked($path, $scope, $scopeCode)) { + throw new CouldNotSaveException( + __( + 'The value you set has already been locked. To change the value, use the --%1 option.', + ConfigSetCommand::OPTION_LOCK + ) + ); + } + + try { + /** @var Config $config */ + $config = $this->configFactory->create(); + $config->setDataByPath($path, $value); + + if (in_array($scope, [ScopeInterface::SCOPE_WEBSITE, ScopeInterface::SCOPE_WEBSITES])) { + $config->setWebsite($scopeCode); + } elseif (in_array($scope, [ScopeInterface::SCOPE_STORE, ScopeInterface::SCOPE_STORES])) { + $config->setStore($scopeCode); + } + + $config->save(); + } catch (\Exception $exception) { + throw new CouldNotSaveException(__('%1', $exception->getMessage()), $exception); + } + } + + /** + * Checks whether configuration is locked in file storage. + * + * @param string $path The path to configuration + * @param string $scope The scope of configuration + * @param string $scopeCode The scope code of configuration + * @return bool + */ + private function isLocked($path, $scope, $scopeCode) + { + $scopePath = $this->configPathResolver->resolve($path, $scope, $scopeCode, System::CONFIG_TYPE); + + return $this->deploymentConfig->get($scopePath) !== null; + } +} diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php new file mode 100644 index 0000000000000..58a93e61781ba --- /dev/null +++ b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php @@ -0,0 +1,134 @@ +deploymentConfig = $deploymentConfig; + $this->deploymentConfigWriter = $writer; + $this->arrayManager = $arrayManager; + $this->configPathResolver = $configPathResolver; + $this->configStructure = $configStructure; + $this->configValueFactory = $configValueFactory; + } + + /** + * Processes lock flow of config:set command. + * Requires read access to filesystem. + * + * {@inheritdoc} + */ + public function process($path, $value, $scope, $scopeCode) + { + try { + $configPath = $this->configPathResolver->resolve($path, $scope, $scopeCode, System::CONFIG_TYPE); + /** @var Structure\Element\Field $field */ + $field = $this->deploymentConfig->isAvailable() + ? $this->configStructure->getElement($path) + : null; + /** @var Value $backendModel */ + $backendModel = $field && $field->hasBackendModel() + ? $field->getBackendModel() + : $this->configValueFactory->create(); + + $backendModel->setPath($path); + $backendModel->setScope($scope); + $backendModel->setScopeId($scopeCode); + $backendModel->setValue($value); + + /** + * Temporary solution until Magento introduce unified interface + * for storing system configuration into database and configuration files. + */ + $backendModel->validateBeforeSave(); + $backendModel->beforeSave(); + + $this->deploymentConfigWriter->saveConfig( + [ConfigFilePool::APP_CONFIG => $this->arrayManager->set($configPath, [], $backendModel->getValue())], + false + ); + + $backendModel->afterSave(); + } catch (\Exception $exception) { + throw new CouldNotSaveException(__('%1', $exception->getMessage()), $exception); + } + } +} diff --git a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php new file mode 100644 index 0000000000000..787624b195361 --- /dev/null +++ b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php @@ -0,0 +1,145 @@ +configSetProcessorFactory = $configSetProcessorFactory; + $this->validator = $validator; + $this->scope = $scope; + + parent::__construct(); + } + + /** + * @inheritdoc + */ + protected function configure() + { + $this->setName('config:set') + ->setDescription('Change system configuration') + ->setDefinition([ + new InputArgument( + static::ARG_PATH, + InputArgument::REQUIRED, + 'Configuration path in format group/section/field_name' + ), + new InputArgument(static::ARG_VALUE, InputArgument::REQUIRED, 'Configuration value'), + new InputOption( + static::OPTION_SCOPE, + null, + InputArgument::OPTIONAL, + 'Configuration scope (default, website, or store)', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ), + new InputOption( + static::OPTION_SCOPE_CODE, + null, + InputArgument::OPTIONAL, + 'Scope code (required only if scope is not \'default\')' + ), + new InputOption( + static::OPTION_LOCK, + 'l', + InputOption::VALUE_NONE, + 'Lock value which prevents modification in the Admin' + ), + ]); + + parent::configure(); + } + + /** + * Creates and run appropriate processor, depending on input options. + * + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + $this->validator->isValid( + $input->getOption(static::OPTION_SCOPE), + $input->getOption(static::OPTION_SCOPE_CODE) + ); + + // Emulating adminhtml scope to be able to read configs. + $this->scope->setCurrentScope(Area::AREA_ADMINHTML); + + $processor = $input->getOption(static::OPTION_LOCK) + ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK) + : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT); + $message = $input->getOption(static::OPTION_LOCK) + ? 'Value was saved and locked.' + : 'Value was saved.'; + + // The processing flow depends on --lock option. + $processor->process( + $input->getArgument(ConfigSetCommand::ARG_PATH), + $input->getArgument(ConfigSetCommand::ARG_VALUE), + $input->getOption(ConfigSetCommand::OPTION_SCOPE), + $input->getOption(ConfigSetCommand::OPTION_SCOPE_CODE) + ); + + $output->writeln('' . $message . ''); + + return Cli::RETURN_SUCCESS; + } catch (\Exception $exception) { + $output->writeln('' . $exception->getMessage() . ''); + + return Cli::RETURN_FAILURE; + } + } +} diff --git a/app/code/Magento/Config/Console/Command/ConfigShow/ValueProcessor.php b/app/code/Magento/Config/Console/Command/ConfigShow/ValueProcessor.php new file mode 100644 index 0000000000000..c60c983c383fa --- /dev/null +++ b/app/code/Magento/Config/Console/Command/ConfigShow/ValueProcessor.php @@ -0,0 +1,89 @@ +scope = $scope; + $this->configStructureFactory = $structureFactory; + $this->configValueFactory = $valueFactory; + } + + /** + * Processes value using backend model. + * + * @param string $scope The scope of configuration. E.g. 'default', 'website' or 'store' + * @param string $scopeCode The scope code of configuration + * @param string $value The value to process + * @param string $path The configuration path for getting backend model. E.g. scope_id/group_id/field_id + * @return string processed value result + */ + public function process($scope, $scopeCode, $value, $path) + { + $areaScope = $this->scope->getCurrentScope(); + $this->scope->setCurrentScope(Area::AREA_ADMINHTML); + /** @var Structure $configStructure */ + $configStructure = $this->configStructureFactory->create(); + $this->scope->setCurrentScope($areaScope); + + /** @var Field $field */ + $field = $configStructure->getElement($path); + + /** @var Value $backendModel */ + $backendModel = $field && $field->hasBackendModel() + ? $field->getBackendModel() + : $this->configValueFactory->create(); + $backendModel->setPath($path); + $backendModel->setScope($scope); + $backendModel->setScopeId($scopeCode); + $backendModel->setValue($value); + $backendModel->afterLoad(); + + return $backendModel->getValue(); + } +} diff --git a/app/code/Magento/Config/Console/Command/ConfigShowCommand.php b/app/code/Magento/Config/Console/Command/ConfigShowCommand.php new file mode 100644 index 0000000000000..5003b0eab725b --- /dev/null +++ b/app/code/Magento/Config/Console/Command/ConfigShowCommand.php @@ -0,0 +1,206 @@ +scopeValidator = $scopeValidator; + $this->configSource = $configSource; + $this->pathResolver = $pathResolver; + $this->valueProcessor = $valueProcessor; + } + + /** + * @inheritdoc + */ + protected function configure() + { + $this->addArgument( + self::INPUT_ARGUMENT_PATH, + InputArgument::OPTIONAL, + 'Configuration path, for example section_id/group_id/field_id' + ); + $this->addOption( + self::INPUT_OPTION_SCOPE, + null, + InputOption::VALUE_OPTIONAL, + 'Scope for configuration, if not specified, then \'default\' scope will be used', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->addOption( + self::INPUT_OPTION_SCOPE_CODE, + null, + InputOption::VALUE_OPTIONAL, + 'Scope code (required only if scope is not `default`)', + '' + ); + $this->setName('config:show') + ->setDescription( + 'Shows configuration value for given path. If path is not specified, all saved values will be shown' + ); + parent::configure(); + } + + /** + * Displays configuration value for given configuration path. + * + * Shows error message if configuration for given path doesn't exist + * or scope/scope-code doesn't pass validation. + * + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + try { + $this->scope = $input->getOption(self::INPUT_OPTION_SCOPE); + $this->scopeCode = $input->getOption(self::INPUT_OPTION_SCOPE_CODE); + $this->inputPath = $input->getArgument(self::INPUT_ARGUMENT_PATH); + + $this->scopeValidator->isValid($this->scope, $this->scopeCode); + $configPath = $this->pathResolver->resolve($this->inputPath, $this->scope, $this->scopeCode); + $configValue = $this->configSource->get($configPath); + + if (empty($configValue)) { + $output->writeln(sprintf( + '%s', + __('Configuration for path: "%1" doesn\'t exist', $this->inputPath)->render() + )); + return Cli::RETURN_FAILURE; + } + + $this->outputResult($output, $configValue, $this->inputPath); + return Cli::RETURN_SUCCESS; + } catch (\Exception $e) { + $output->writeln(sprintf('%s', $e->getMessage())); + return Cli::RETURN_FAILURE; + } + } + + /** + * Outputs single configuration value or list of values if array given. + * + * @param OutputInterface $output an OutputInterface instance + * @param string|array $configValue can be string when $configPath is a path for concreate field. + * In other cases $configValue should be an array + * ```php + * [ + * 'section' => + * [ + * 'group1' => + * [ + * 'field1' => 'value1', + * 'field2' => 'value2' + * ], + * 'group2' => + * [ + * 'field1' => 'value3' + * ] + * ] + * ] + * ``` + * @param string $configPath base configuration path + * @return void + */ + private function outputResult(OutputInterface $output, $configValue, $configPath) + { + if (!is_array($configValue)) { + $value = $this->valueProcessor->process($this->scope, $this->scopeCode, $configValue, $configPath); + $output->writeln($this->inputPath === $configPath ? $value : sprintf("%s - %s", $configPath, $value)); + } elseif (is_array($configValue)) { + foreach ($configValue as $name => $value) { + $childPath = empty($configPath) ? $name : ($configPath . '/' . $name); + $this->outputResult($output, $value, $childPath); + } + } + } +} diff --git a/app/code/Magento/Config/Console/CommandList.php b/app/code/Magento/Config/Console/CommandList.php new file mode 100644 index 0000000000000..8915d0e9c8f62 --- /dev/null +++ b/app/code/Magento/Config/Console/CommandList.php @@ -0,0 +1,48 @@ +objectManager = $objectManager; + } + + /** + * {@inheritdoc} + */ + public function getCommands() + { + $commands = []; + $commandClasses = [ + ConfigSetCommand::class, + ]; + + foreach ($commandClasses as $class) { + $commands[] = $this->objectManager->get($class); + } + + return $commands; + } +} diff --git a/app/code/Magento/Config/Controller/Adminhtml/System/AbstractConfig.php b/app/code/Magento/Config/Controller/Adminhtml/System/AbstractConfig.php index 1d43b28daaf15..e7d8ed66b2cf4 100644 --- a/app/code/Magento/Config/Controller/Adminhtml/System/AbstractConfig.php +++ b/app/code/Magento/Config/Controller/Adminhtml/System/AbstractConfig.php @@ -1,6 +1,6 @@ getUrlValidator()->isValid($value, ['http', 'https']); } /** @@ -216,4 +223,18 @@ public function afterSave() } return parent::afterSave(); } + + /** + * Get URL Validator + * + * @deprecated + * @return UrlValidator + */ + private function getUrlValidator() + { + if (!$this->urlValidator) { + $this->urlValidator = ObjectManager::getInstance()->get(UrlValidator::class); + } + return $this->urlValidator; + } } diff --git a/app/code/Magento/Config/Model/Config/Backend/Cache.php b/app/code/Magento/Config/Model/Config/Backend/Cache.php index ba437c0f971b2..f6bc92e033927 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Cache.php +++ b/app/code/Magento/Config/Model/Config/Backend/Cache.php @@ -1,6 +1,6 @@ serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + } + /** * @return void */ protected function _afterLoad() { - if (!is_array($this->getValue())) { - $value = $this->getValue(); - $this->setValue(empty($value) ? false : unserialize($value)); + $value = $this->getValue(); + if (!is_array($value)) { + $this->setValue(empty($value) ? false : $this->serializer->unserialize($value)); } } @@ -24,8 +58,9 @@ protected function _afterLoad() public function beforeSave() { if (is_array($this->getValue())) { - $this->setValue(serialize($this->getValue())); + $this->setValue($this->serializer->serialize($this->getValue())); } - return parent::beforeSave(); + parent::beforeSave(); + return $this; } } diff --git a/app/code/Magento/Config/Model/Config/Backend/Serialized/ArraySerialized.php b/app/code/Magento/Config/Model/Config/Backend/Serialized/ArraySerialized.php index d0e5ec5efe1ad..f147b0494f46b 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Serialized/ArraySerialized.php +++ b/app/code/Magento/Config/Model/Config/Backend/Serialized/ArraySerialized.php @@ -1,6 +1,6 @@ _mutableConfig->setValue( - \Magento\Store\Model\Store::XML_PATH_STORE_IN_URL, - $this->getValue(), - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); $this->_cacheManager->clean(); return parent::afterSave(); } diff --git a/app/code/Magento/Config/Model/Config/Backend/Translate.php b/app/code/Magento/Config/Model/Config/Backend/Translate.php index 5e10fa33e60e8..2b5ed2191eaf0 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Translate.php +++ b/app/code/Magento/Config/Model/Config/Backend/Translate.php @@ -1,6 +1,6 @@ placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); + $this->source = $source; + } + + /** + * Retrieves comments for config export file. + * + * @return string + */ + public function get() + { + $comment = ''; + $fields = $this->source->getExcludedFields(); + foreach ($fields as $path) { + $comment .= "\n" . $this->placeholder->generate($path) . ' for ' . $path ; + } + if ($comment) { + $comment = 'The configuration file doesn\'t contain sensitive data for security reasons. ' + . 'Sensitive data can be stored in the following environment variables:' + . $comment; + } + return $comment; + } +} diff --git a/app/code/Magento/Config/Model/Config/Export/ExcludeList.php b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php new file mode 100644 index 0000000000000..ef43664153515 --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Export/ExcludeList.php @@ -0,0 +1,55 @@ +configs = $configs; + } + + /** + * Check whether config item is excluded from export + * + * @param string $path + * @return bool + */ + public function isPresent($path) + { + return !empty($this->configs[$path]) ; + } + + /** + * Retrieves all excluded field paths for export + * + * @return array + */ + public function get() + { + return array_keys( + array_filter( + $this->configs, + function ($value) { + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + } + ) + ); + } +} diff --git a/app/code/Magento/Config/Model/Config/Factory.php b/app/code/Magento/Config/Model/Config/Factory.php index 34cf168809afe..312e583755453 100644 --- a/app/code/Magento/Config/Model/Config/Factory.php +++ b/app/code/Magento/Config/Model/Config/Factory.php @@ -1,6 +1,6 @@ filesystem = $filesystem; + $this->placeholder = $placeholder; + } + + /** + * Retrieves config paths from comment section of the file. + * Example of comment: + * * CONFIG__DEFAULT__SOME__CONF__PATH_ONE + * * CONFIG__DEFAULT__SOME__CONF__PATH_TWO + * This method will return: + * array( + * 'CONFIG__DEFAULT__SOME__CONF__PATH_ONE' => 'some/conf/path_one', + * 'CONFIG__DEFAULT__SOME__CONF__PATH_TWO' => 'some/conf/path_two' + * ); + * + * @param string $fileName + * @return array + * @throws FileSystemException + */ + public function execute($fileName) + { + $fileContent = $this->filesystem + ->getDirectoryRead(DirectoryList::CONFIG) + ->readFile($fileName); + + $pattern = sprintf('/\s+\*\s+(?P%s.*?)\s/', preg_quote(Environment::PREFIX)); + preg_match_all($pattern, $fileContent, $matches); + + if (!isset($matches['placeholder'])) { + return []; + } + + $configs = []; + foreach ($matches['placeholder'] as $placeholder) { + $path = $this->placeholder->restore($placeholder); + $path = preg_replace('/^' . ScopeConfigInterface::SCOPE_TYPE_DEFAULT . '\//', '', $path); + $configs[$placeholder] = $path; + } + + return $configs; + } +} diff --git a/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php new file mode 100644 index 0000000000000..e9cd619396c4d --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Processor/EnvironmentPlaceholder.php @@ -0,0 +1,70 @@ +placeholderFactory = $placeholderFactory; + $this->arrayManager = $arrayManager; + $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); + } + + /** + * Method extracts environment variables. + * If environment variable is matching the desired rule - it's being used as value. + * + * {@inheritdoc} + */ + public function process(array $config) + { + $environmentVariables = $_ENV; + + foreach ($environmentVariables as $template => $value) { + if (!$this->placeholder->isApplicable($template)) { + continue; + } + + $config = $this->arrayManager->set( + $this->placeholder->restore($template), + $config, + $value + ); + } + + return $config; + } +} diff --git a/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php new file mode 100644 index 0000000000000..de13f12a3116c --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Reader/Source/Deployed/SettingChecker.php @@ -0,0 +1,119 @@ +config = $config; + $this->scopeCodeResolver = $scopeCodeResolver; + $this->placeholder = $placeholderFactory->create(PlaceholderFactory::TYPE_ENVIRONMENT); + } + + /** + * Check that setting defined in deployed configuration + * + * @param string $path + * @param string $scope + * @param string|null $scopeCode + * @return boolean + */ + public function isReadOnly($path, $scope, $scopeCode = null) + { + $config = $this->getEnvValue( + $this->placeholder->generate($path, $scope, $scopeCode) + ); + + if (null === $config) { + $config = $this->config->get($this->resolvePath($scope, $scopeCode) . "/" . $path); + } + + return $config !== null; + } + + /** + * Check that there is value for generated placeholder + * + * Placeholder is generated from values of $path, $scope and $scopeCode + * + * @param string $path + * @param string $scope + * @param string $scopeCode + * @param string|null $scopeCode + * @return string|null + */ + public function getPlaceholderValue($path, $scope, $scopeCode = null) + { + return $this->getEnvValue($this->placeholder->generate($path, $scope, $scopeCode)); + } + + /** + * Retrieve value of environment variable by placeholder + * + * @param string $placeholder + * @return string|null + */ + public function getEnvValue($placeholder) + { + if ($this->placeholder->isApplicable($placeholder) && isset($_ENV[$placeholder])) { + return $_ENV[$placeholder]; + } + + return null; + } + + /** + * Resolve path by scope and scope code + * + * @param string $scope + * @param string $scopeCode + * @return string + */ + private function resolvePath($scope, $scopeCode) + { + $scopePath = 'system/' . $scope; + + if ($scope != ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + $scopePath .= '/' . $this->scopeCodeResolver->resolve($scope, $scopeCode); + } + + return $scopePath; + } +} diff --git a/app/code/Magento/Config/Model/Config/SchemaLocator.php b/app/code/Magento/Config/Model/Config/SchemaLocator.php index 255dee9a66144..06b18ad6e2cc8 100644 --- a/app/code/Magento/Config/Model/Config/SchemaLocator.php +++ b/app/code/Magento/Config/Model/Config/SchemaLocator.php @@ -2,7 +2,7 @@ /** * System configuration schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Config\Model\Config; diff --git a/app/code/Magento/Config/Model/Config/ScopeDefiner.php b/app/code/Magento/Config/Model/Config/ScopeDefiner.php index c114e6b8b4cde..529672cc2f4e6 100644 --- a/app/code/Magento/Config/Model/Config/ScopeDefiner.php +++ b/app/code/Magento/Config/Model/Config/ScopeDefiner.php @@ -1,6 +1,6 @@ getElementVisibility()->isHidden($this->getPath())) { + return false; + } + if (isset($this->_data['if_module_enabled']) && !$this->moduleManager->isOutputEnabled($this->_data['if_module_enabled'])) { return false; @@ -203,4 +213,21 @@ public function getPath($fieldPrefix = '') { return $this->_getPath($this->getId(), $fieldPrefix); } + + /** + * Get instance of ElementVisibilityInterface. + * + * @return ElementVisibilityInterface + * @deprecated Added to not break backward compatibility of the constructor signature + * by injecting the new dependency directly. + * The method can be removed in a future major release, when constructor signature can be changed. + */ + public function getElementVisibility() + { + if (null === $this->elementVisibility) { + $this->elementVisibility = ObjectManager::getInstance()->get(ElementVisibilityInterface::class); + } + + return $this->elementVisibility; + } } diff --git a/app/code/Magento/Config/Model/Config/Structure/AbstractMapper.php b/app/code/Magento/Config/Model/Config/Structure/AbstractMapper.php index c259c88679ca7..78f1b22c42326 100644 --- a/app/code/Magento/Config/Model/Config/Structure/AbstractMapper.php +++ b/app/code/Magento/Config/Model/Config/Structure/AbstractMapper.php @@ -1,6 +1,6 @@ Settings > Configuration page + * in Admin Panel in Production mode. + */ +class ConcealInProductionConfigList implements ElementVisibilityInterface +{ + /** + * The list of form element paths with concrete visibility status. + * + * E.g. + * + * ```php + * [ + * 'general/locale/code' => ElementVisibilityInterface::DISABLED, + * 'general/country' => ElementVisibilityInterface::HIDDEN, + * ]; + * ``` + * + * It means that: + * - field Locale (in group Locale Options in section General) will be disabled + * - group Country Options (in section General) will be hidden + * + * @var array + */ + private $configs = []; + + /** + * The object that has information about the state of the system. + * + * @var State + */ + private $state; + + /** + * @param State $state The object that has information about the state of the system + * @param array $configs The list of form element paths with concrete visibility status. + */ + public function __construct(State $state, array $configs = []) + { + $this->state = $state; + $this->configs = $configs; + } + + /** + * @inheritdoc + */ + public function isHidden($path) + { + $path = $this->normalizePath($path); + return $this->state->getMode() === State::MODE_PRODUCTION + && !empty($this->configs[$path]) + && $this->configs[$path] === static::HIDDEN; + } + + /** + * @inheritdoc + */ + public function isDisabled($path) + { + $path = $this->normalizePath($path); + if ($this->state->getMode() === State::MODE_PRODUCTION) { + while (true) { + if (!empty($this->configs[$path])) { + return $this->configs[$path] === static::DISABLED; + } + + $position = strripos($path, '/'); + if ($position === false) { + break; + } + $path = substr($path, 0, $position); + } + } + + return false; + } + + /** + * Returns normalized path. + * + * @param string $path The path to be normalized + * @return string The normalized path + */ + private function normalizePath($path) + { + return trim($path, '/'); + } +} diff --git a/app/code/Magento/Config/Model/Config/Structure/Converter.php b/app/code/Magento/Config/Model/Config/Structure/Converter.php index 45c46098a0313..4ac6f8aa9c3c4 100644 --- a/app/code/Magento/Config/Model/Config/Structure/Converter.php +++ b/app/code/Magento/Config/Model/Config/Structure/Converter.php @@ -1,6 +1,6 @@ Settings > Configuration page in Admin Panel. + */ +class ElementVisibilityComposite implements ElementVisibilityInterface +{ + /** + * List of objects which implements ElementVisibilityInterface for + * checking of visibility of form elements on Configuration page. + * + * @var ElementVisibilityInterface[] + */ + private $visibility = []; + + /** + * @param ElementVisibilityInterface[] $visibility List of objects which define visibility status of form elements + * under its own conditions. + * @throws ConfigurationMismatchException It is thrown if some object from list $visibility + * implements the wrong interface. + */ + public function __construct(array $visibility = []) + { + foreach ($visibility as $name => $item) { + if (!$item instanceof ElementVisibilityInterface) { + throw new ConfigurationMismatchException( + __( + '%1: Instance of %2 is expected, got %3 instead', + $name, + ElementVisibilityInterface::class, + get_class($item) + ) + ); + } + } + + $this->visibility = $visibility; + } + + /** + * @inheritdoc + */ + public function isHidden($path) + { + foreach ($this->visibility as $element) { + if ($element->isHidden($path)) { + return true; + } + } + + return false; + } + + /** + * @inheritdoc + */ + public function isDisabled($path) + { + foreach ($this->visibility as $element) { + if ($element->isDisabled($path)) { + return true; + } + } + + return false; + } +} diff --git a/app/code/Magento/Config/Model/Config/Structure/ElementVisibilityInterface.php b/app/code/Magento/Config/Model/Config/Structure/ElementVisibilityInterface.php new file mode 100644 index 0000000000000..023166b0c358f --- /dev/null +++ b/app/code/Magento/Config/Model/Config/Structure/ElementVisibilityInterface.php @@ -0,0 +1,36 @@ + Settings > Configuration page in Admin Panel + * by their paths in the system.xml structure. + */ +interface ElementVisibilityInterface +{ + /**#@+ + * Constants of statuses for form elements. + */ + const HIDDEN = 'hidden'; + const DISABLED = 'disabled'; + /**#@-*/ + + /** + * Check whether form element is disabled by path. + * + * @param string $path The path of form element in the system.xml structure + * @return bool + */ + public function isDisabled($path); + + /** + * Check whether form element is hidden in form by path. + * + * @param string $path The path of form element in the system.xml structure + * @return bool + */ + public function isHidden($path); +} diff --git a/app/code/Magento/Config/Model/Config/Structure/Mapper/Attribute/Inheritance.php b/app/code/Magento/Config/Model/Config/Structure/Mapper/Attribute/Inheritance.php index d132117ccbaec..8286728a4c220 100644 --- a/app/code/Magento/Config/Model/Config/Structure/Mapper/Attribute/Inheritance.php +++ b/app/code/Magento/Config/Model/Config/Structure/Mapper/Attribute/Inheritance.php @@ -1,6 +1,6 @@ deploymentConfig = $deploymentConfig; + } + + /** + * Generates placeholder like CONFIG__DEFAULT__TEST__TEST_VALUE + * + * @inheritdoc + */ + public function generate($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + { + $parts = $scopeType ? [$scopeType] : []; + + if ($scopeType !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT && $scopeCode) { + $parts[] = $scopeCode; + } + + $parts[] = $path; + + $template = implode('__', $parts); + $template = str_replace('/', '__', $template); + $template = static::PREFIX . $template; + $template = strtoupper($template); + + return $template; + } + + /** + * @inheritdoc + */ + public function restore($template) + { + $template = preg_replace('/^' . static::PREFIX . '/', '', $template); + $template = str_replace('__', '/', $template); + $template = strtolower($template); + + return $template; + } + + /** + * @inheritdoc + */ + public function isApplicable($placeholder) + { + return 1 === preg_match('/^' . static::PREFIX . '([a-zA-Z]+)([a-zA-Z0-9_])*$/', $placeholder); + } +} diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php new file mode 100644 index 0000000000000..bc03d35f84a6c --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderFactory.php @@ -0,0 +1,59 @@ +objectManager = $objectManager; + $this->types = $types; + } + + /** + * Create placeholder + * + * @param string $type + * @return PlaceholderInterface + * @throws LocalizedException + */ + public function create($type) + { + if (!isset($this->types[$type])) { + throw new LocalizedException(__('There is no defined type ' . $type)); + } + + $object = $this->objectManager->create($this->types[$type]); + + if (!$object instanceof PlaceholderInterface) { + throw new LocalizedException(__('Object is not instance of ' . PlaceholderInterface::class)); + } + + return $object; + } +} diff --git a/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php new file mode 100644 index 0000000000000..0050dc46d082f --- /dev/null +++ b/app/code/Magento/Config/Model/Placeholder/PlaceholderInterface.php @@ -0,0 +1,40 @@ +sourceMock = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->sourceMockTwo = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->excludeListMock = $this->getMockBuilder(ExcludeList::class) + ->disableOriginalConstructor() + ->getMock(); + + $sources = [ + [ + 'source' => $this->sourceMockTwo, + 'sortOrder' => 100 + ], + [ + 'source' => $this->sourceMock, + 'sortOrder' => 10 + ], + + ]; + + $this->model = new DumpConfigSourceAggregated($this->excludeListMock, $sources); + } + + public function testGet() + { + $path = ''; + $data = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [ + 'base_url' => 'https://test.local', + ] + ] + ], + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ] + ] + ]; + + $this->sourceMock->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn($data); + $this->sourceMockTwo->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value2']); + $this->excludeListMock->expects($this->any()) + ->method('isPresent') + ->willReturnMap([ + ['web/unsecure/base_url', false], + ['web/secure/base_url', true], + ['test1/test2/test/3', false] + ]); + + $this->assertEquals( + [ + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ], + ], + 'key' => 'value2', + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [] + ] + ], + ], + $this->model->get($path) + ); + } + + public function testGetExcludedFields() + { + $path = ''; + $data = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://test.local', + ], + 'secure' => [ + 'base_url' => 'https://test.local', + ] + ] + ], + 'test' => [ + 'test' => [ + 'test1' => [ + 'test2' => [ + 'test3' => 5, + ] + ] + ] + ] + ]; + + $this->sourceMock->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn($data); + $this->sourceMockTwo->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value2']); + $this->excludeListMock->expects($this->any()) + ->method('isPresent') + ->willReturnMap([ + ['web/unsecure/base_url', false], + ['web/secure/base_url', true], + ['test1/test2/test/3', false] + ]); + + $this->assertEquals( + ['web/secure/base_url'], + $this->model->getExcludedFields() + ); + } +} diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Source/EnvironmentConfigSourceTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Source/EnvironmentConfigSourceTest.php new file mode 100644 index 0000000000000..f28f54798df3d --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/App/Config/Source/EnvironmentConfigSourceTest.php @@ -0,0 +1,113 @@ +arrayManagerMock = $this->getMockBuilder(ArrayManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->placeholderMock = $this->getMockBuilder(PlaceholderInterface::class) + ->getMockForAbstractClass(); + + /** @var PlaceholderFactory|\PHPUnit_Framework_MockObject_MockObject $placeholderFactoryMock */ + $placeholderFactoryMock = $this->getMockBuilder(PlaceholderFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $placeholderFactoryMock->expects($this->once()) + ->method('create') + ->with(PlaceholderFactory::TYPE_ENVIRONMENT) + ->willReturn($this->placeholderMock); + + $this->source = new EnvironmentConfigSource($this->arrayManagerMock, $placeholderFactoryMock); + } + + /** + * @param string $path + * @param array|string $expectedResult + * @dataProvider getDataProvider + */ + public function testGet($path, $expectedResult) + { + $placeholder = 'CONFIG__UNIT__TEST__VALUE'; + $configValue = 'test_value'; + $configPath = 'unit/test/value'; + $expectedArray = ['unit' => ['test' => ['value' => $configValue]]]; + $_ENV[$placeholder] = $configValue; + + $this->placeholderMock->expects($this->any()) + ->method('isApplicable') + ->willReturnMap([ + [$placeholder, true] + ]); + $this->placeholderMock->expects($this->once()) + ->method('restore') + ->with($placeholder) + ->willReturn($configPath); + $this->arrayManagerMock->expects($this->once()) + ->method('set') + ->with($configPath, [], $configValue) + ->willReturn($expectedArray); + + $this->assertEquals($expectedResult, $this->source->get($path)); + } + + /** + * @return array + */ + public function getDataProvider() + { + return [ + ['', ['unit' => ['test' => ['value' => 'test_value']]]], + ['unit', ['test' => ['value' => 'test_value']]], + ['unit/test', ['value' => 'test_value']], + ['unit/test/value', 'test_value'], + ['wrong/path', []], + ]; + } + + public function testGetWithoutEnvCongigurationVariables() + { + $expectedArray = []; + + $this->placeholderMock->expects($this->any()) + ->method('isApplicable') + ->willReturn(false); + $this->placeholderMock->expects($this->never()) + ->method('restore'); + $this->arrayManagerMock->expects($this->never()) + ->method('set'); + + $this->assertSame($expectedArray, $this->source->get()); + } + + public function tearDown() + { + unset($_ENV['CONFIG__UNIT__TEST__VALUE']); + } +} diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Source/ModularConfigSourceTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Source/ModularConfigSourceTest.php new file mode 100644 index 0000000000000..6e9bdf69f6ab8 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/App/Config/Source/ModularConfigSourceTest.php @@ -0,0 +1,43 @@ +reader = $this->getMockBuilder(Reader::class) + ->disableOriginalConstructor() + ->getMock(); + $this->source = new ModularConfigSource($this->reader); + } + + public function testGet() + { + $this->reader->expects($this->once()) + ->method('read') + ->willReturn(['data' => ['path' => 'value']]); + $this->assertEquals('value', $this->source->get('path')); + } +} diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Source/RuntimeConfigSourceTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Source/RuntimeConfigSourceTest.php new file mode 100644 index 0000000000000..f603355481344 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/App/Config/Source/RuntimeConfigSourceTest.php @@ -0,0 +1,136 @@ +collectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->scopeCodeResolver = $this->getMockBuilder(ScopeCodeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->converter = $this->getMockBuilder(Converter::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configItem = $this->getMockBuilder(Value::class) + ->disableOriginalConstructor() + ->setMethods(['getScope', 'getPath', 'getValue']) + ->getMock(); + $this->configItemTwo = $this->getMockBuilder(Value::class) + ->disableOriginalConstructor() + ->setMethods(['getScope', 'getPath', 'getValue', 'getScopeId']) + ->getMock(); + $this->configSource = new RuntimeConfigSource( + $this->collectionFactory, + $this->scopeCodeResolver, + $this->converter + ); + } + + public function testGet() + { + $scope = 'websites'; + $scopeCode = 'myWebsites'; + $this->collectionFactory->expects($this->once()) + ->method('create') + ->willReturn([$this->configItem, $this->configItemTwo]); + $this->configItem->expects($this->exactly(2)) + ->method('getScope') + ->willReturn(ScopeConfigInterface::SCOPE_TYPE_DEFAULT); + $this->configItem->expects($this->once()) + ->method('getPath') + ->willReturn('dev/test/setting'); + $this->configItem->expects($this->once()) + ->method('getValue') + ->willReturn(true); + + $this->configItemTwo->expects($this->exactly(3)) + ->method('getScope') + ->willReturn($scope); + $this->configItemTwo->expects($this->once()) + ->method('getScopeId') + ->willReturn($scopeCode); + $this->configItemTwo->expects($this->once()) + ->method('getPath') + ->willReturn('dev/test/setting2'); + $this->configItemTwo->expects($this->once()) + ->method('getValue') + ->willReturn(false); + $this->scopeCodeResolver->expects($this->once()) + ->method('resolve') + ->with($scope, $scopeCode) + ->willReturnArgument(1); + $this->converter->expects($this->exactly(2)) + ->method('convert') + ->withConsecutive( + [['dev/test/setting' => true]], + [['dev/test/setting2' => false]] + ) + ->willReturnOnConsecutiveCalls( + ['dev/test/setting' => true], + ['dev/test/setting2' => false] + ); + + $this->assertEquals( + [ + 'default' => [ + 'dev/test/setting' => true + ], + 'websites' => [ + 'myWebsites' => [ + 'dev/test/setting2' => false + ] + ] + ], + $this->configSource->get() + ); + } +} diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php new file mode 100644 index 0000000000000..393402c33fde2 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php @@ -0,0 +1,153 @@ +source = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->postProcessor = $this->getMockBuilder(PostProcessorInterface::class) + ->getMockForAbstractClass(); + $this->fallback = $this->getMockBuilder(Fallback::class) + ->disableOriginalConstructor() + ->getMock(); + $this->cache = $this->getMockBuilder(FrontendInterface::class) + ->getMockForAbstractClass(); + $this->preProcessor = $this->getMockBuilder(PreProcessorInterface::class) + ->getMockForAbstractClass(); + $this->serializer = $this->getMockBuilder(SerializerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configType = new System( + $this->source, + $this->postProcessor, + $this->fallback, + $this->cache, + $this->serializer, + $this->preProcessor + ); + } + + /** + * @param bool $isCached + * @dataProvider getDataProvider + */ + public function testGet($isCached) + { + $path = 'default/dev/unsecure/url'; + $url = 'http://magento.test/'; + $data = [ + 'default' => [ + 'dev' => [ + 'unsecure' => [ + 'url' => $url + ] + ] + ] + ]; + + $this->cache->expects($this->once()) + ->method('load') + ->with(System::CONFIG_TYPE) + ->willReturn($isCached ? $data : null); + + if ($isCached) { + $this->serializer->expects($this->once()) + ->method('unserialize') + ->willReturn($data); + } + + if (!$isCached) { + $this->serializer->expects($this->once()) + ->method('serialize') + ->willReturn(serialize($data)); + $this->source->expects($this->once()) + ->method('get') + ->willReturn($data); + $this->fallback->expects($this->once()) + ->method('process') + ->with($data) + ->willReturnArgument(0); + $this->preProcessor->expects($this->once()) + ->method('process') + ->with($data) + ->willReturnArgument(0); + $this->postProcessor->expects($this->once()) + ->method('process') + ->with($data) + ->willReturnArgument(0); + $this->cache->expects($this->once()) + ->method('save') + ->with( + serialize($data), + System::CONFIG_TYPE, + [System::CACHE_TAG] + ); + } + + $this->assertEquals($url, $this->configType->get($path)); + } + + /** + * @return array + */ + public function getDataProvider() + { + return [ + [true], + [false] + ]; + } +} diff --git a/app/code/Magento/Config/Test/Unit/Block/System/Config/DwstreeTest.php b/app/code/Magento/Config/Test/Unit/Block/System/Config/DwstreeTest.php index 1fb2735600d4c..59db6793c9a3c 100644 --- a/app/code/Magento/Config/Test/Unit/Block/System/Config/DwstreeTest.php +++ b/app/code/Magento/Config/Test/Unit/Block/System/Config/DwstreeTest.php @@ -1,6 +1,6 @@ getMockForAbstractClass( + $this->model = $this->getMockForAbstractClass( \Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray::class, [], '', @@ -19,12 +23,15 @@ public function testGetArrayRows() true, ['escapeHtml'] ); - $block->expects($this->any())->method('escapeHtml')->will($this->returnArgument(0)); + } + public function testGetArrayRows() + { + $this->model->expects($this->any())->method('escapeHtml')->will($this->returnArgument(0)); $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $element = $objectManager->getObject(\Magento\Framework\Data\Form\Element\Multiselect::class); $element->setValue([['tet' => 'tst', 'data&1' => 'da&ta1']]); - $block->setElement($element); + $this->model->setElement($element); $this->assertEquals( [ new \Magento\Framework\DataObject( @@ -36,7 +43,17 @@ public function testGetArrayRows() ] ), ], - $block->getArrayRows() + $this->model->getArrayRows() ); } + + public function testGetAddButtonLabel() + { + $contextMock = $this->getMockBuilder(\Magento\Backend\Block\Template\Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->model->__construct($contextMock); + + $this->assertEquals("Add", $this->model->getAddButtonLabel()); + } } diff --git a/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/FileTest.php b/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/FileTest.php index 566f74c30ea29..76a74090efc8e 100644 --- a/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/FileTest.php +++ b/app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/FileTest.php @@ -1,6 +1,6 @@ _formMock->expects( - $this->exactly(2) + $this->once() )->method( 'getHtmlIdPrefix' )->will( $this->returnValue('test_prefix_') ); $this->_formMock->expects( - $this->exactly(2) + $this->once() )->method( 'getHtmlIdSuffix' )->will( @@ -57,7 +57,7 @@ public function testGetAfterElementHtml() $actual = $this->_object->getAfterElementHtml(); - $this->assertStringEndsWith($afterHtmlCode, $actual); + $this->assertStringEndsWith('' . $afterHtmlCode, $actual); $this->assertStringStartsWith(' \ No newline at end of file + diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/attribute/set/js.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/attribute/set/js.phtml index ff4d27dc6852b..da52cf1d16c89 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/attribute/set/js.phtml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/attribute/set/js.phtml @@ -1,7 +1,7 @@
    escapeHtml( - __('Select values from each attribute to include in this product. Each unique combination of values creates a unigue product SKU.') + __('Select values from each attribute to include in this product. Each unique combination of values creates a unique product SKU.') );?>
    diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml index 24bfcabcacea2..5fd0aca0e3be2 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml index 1366208038e0f..5fb4cc6420557 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/configurable_associated_product_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_attributes_listing.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_attributes_listing.xml index fd7759725e4bc..cac255af99610 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_attributes_listing.xml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_attributes_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_form.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_form.xml index 2896efca648e6..a928988a29cd9 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_form.xml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/ui_component/product_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/css/configurable-product.css b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/css/configurable-product.css index 88a8e3876832a..30d75898e79bc 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/css/configurable-product.css +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/css/configurable-product.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js index ecc960bdb9ea5..98461addf4c4f 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/associated-product-insert-listing.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/container-configurable-handler.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/container-configurable-handler.js index 542a9e492d586..e3834bc3464c1 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/container-configurable-handler.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/container-configurable-handler.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js index 107fa05af1d3d..99a495a509179 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-warning.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-warning.js index 3c0b5b82633cc..210361945c541 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-warning.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-warning.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js index ffabd9a8627df..d11acc8cc9699 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/dynamic-rows-configurable.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -32,6 +32,7 @@ define([ identificationProperty: 'id', 'attribute_set_id': '', attributesTmp: [], + changedFlag: 'was_changed', listens: { 'insertDataFromGrid': 'processingInsertDataFromGrid', 'insertDataFromWizard': 'processingInsertDataFromWizard', @@ -393,9 +394,9 @@ define([ 'thumbnail': row.thumbnail, 'attributes': attributesText }; + product[this.changedFlag] = true; product[this.canEditField] = row.editable; product[this.newProductField] = row.newProduct; - tmpArray.push(product); }, this); @@ -515,6 +516,7 @@ define([ tmpArray[rowIndex].status = 1; } + tmpArray[rowIndex][this.changedFlag] = true; this.unionInsertData(tmpArray); } }); diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/file-uploader.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/file-uploader.js index 37f183197dae0..a90d977da6056 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/file-uploader.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/file-uploader.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/modal-configurable.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/modal-configurable.js index 81f1387eb4f46..b0dfe14fe9d6b 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/modal-configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/modal-configurable.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/price-configurable.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/price-configurable.js new file mode 100644 index 0000000000000..005bc60aeada3 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/price-configurable.js @@ -0,0 +1,59 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'underscore', + 'uiRegistry', + 'Magento_Ui/js/form/element/abstract' +], function (_, registry, Abstract) { + 'use strict'; + + return Abstract.extend({ + defaults: { + listens: { + isConfigurable: 'handlePriceValue' + }, + imports: { + isConfigurable: '!ns = ${ $.ns }, index = configurable-matrix:isEmpty' + }, + modules: { + createConfigurableButton: '${$.createConfigurableButton}' + } + }, + + /** + * Invokes initialize method of parent class, + * contains initialization logic + */ + initialize: function () { + this._super(); + + return this; + }, + + /** + * Calls 'initObservable' of parent + * + * @returns {Object} Chainable. + */ + initObservable: function () { + this._super() + .observe(['content']); + + return this; + }, + + /** + * Disable and clear price if product type changed to configurable + * + * @param {String} isConfigurable + */ + handlePriceValue: function (isConfigurable) { + if (isConfigurable) { + this.disable(); + this.clear(); + } + } + }); +}); diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable-type-handler.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable-type-handler.js index ed881be011d7f..857dd8cfa38e8 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable-type-handler.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable-type-handler.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable.js index 988f5f963e2fb..df3b1638f61d1 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/configurable.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /**************************** CONFIGURABLE PRODUCT **************************/ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/options/price-type-handler.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/options/price-type-handler.js index 4a9edda0eb496..cd354741bb061 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/options/price-type-handler.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/options/price-type-handler.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* @@ -80,4 +80,4 @@ define([ } }; }); -*/ \ No newline at end of file +*/ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/paging/sizes.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/paging/sizes.js index 92a83f1bbdd49..386c486cea7b7 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/paging/sizes.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/paging/sizes.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/product-grid.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/product-grid.js index 4d1867669ade0..ce2fd9ac5ea80 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/product-grid.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/product-grid.js @@ -1,6 +1,6 @@ // jscs:disable requireDotNotation /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -8,7 +8,8 @@ define([ 'jquery', 'Magento_Ui/js/core/app', 'underscore', - 'notification' + 'notification', + 'mage/translate' ], function (Component, $, bootstrap, _) { 'use strict'; @@ -221,9 +222,7 @@ define([ if (data.items.length) { this.productsModal.notification('add', { - message: $.mage.__( - 'Choose a new product to delete and replace the current product configuration.' - ), + message: $.mage.__('Choose a new product to delete and replace the current product configuration.'), messageContainer: this.gridSelector }); } else { diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js index e16ea059c2b1f..c3c4bc2336a1b 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/attributes_values.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ // jscs:disable jsDoc diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js index f6769b0d0a9f9..ae4a51fb3b0bd 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js index 3653e91894c29..18a1b30c051ce 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/select_attributes.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ // jscs:disable jsDoc @@ -51,9 +51,13 @@ define([ this.setNotificationMessage(); }, setNotificationMessage: function () { + /*eslint-disable max-len*/ + var msg = $.mage.__('When you remove or add an attribute, we automatically update all configurations and you will need to recreate current configurations manually.'); + + /*eslint-enable max-len*/ + if (this.mode === 'edit') { - this.wizard.setNotificationMessage($.mage.__('When you remove or add an attribute, we automatically ' + - 'update all configurations and you will need to recreate current configurations manually.')); + this.wizard.setNotificationMessage(msg); } }, doSelectSavedAttributes: function () { diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js index c0d1dd642c8b9..1d504cda1738b 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/summary.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ // jscs:disable jsDoc diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js index 45bd795572d04..ff83a9828c180 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/variations.js @@ -1,6 +1,6 @@ // jscs:disable requireDotNotation /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ // jscs:disable jsDoc diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/product/product.css b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/product/product.css index cf7a314d8636e..69b45d7fc6552 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/product/product.css +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/product/product.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/actions-list.html b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/actions-list.html index b423b66971b06..290491a938b05 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/actions-list.html +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/actions-list.html @@ -1,6 +1,6 @@ @@ -41,4 +41,4 @@ "> -
    \ No newline at end of file +
    diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-html.html b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-html.html index 8611ea9b3d03b..bb6b3556734fe 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-html.html +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-html.html @@ -1,6 +1,6 @@ @@ -10,4 +10,4 @@ css: {_disabled: disabled} "> - \ No newline at end of file + diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-status.html b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-status.html index c66c058668cff..4006a8937d2df 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-status.html +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/cell-status.html @@ -1,6 +1,6 @@ @@ -10,4 +10,4 @@ css: {_disabled: disabled} "> - \ No newline at end of file + diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/file-uploader.html b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/file-uploader.html index 8fd1604fafb10..8bdb919d138a9 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/file-uploader.html +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/components/file-uploader.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/variations/steps/summary-grid.html b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/variations/steps/summary-grid.html index ada2e2205e9fb..4ef980d98bed8 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/variations/steps/summary-grid.html +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/template/variations/steps/summary-grid.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml new file mode 100644 index 0000000000000..0ae2972fd36aa --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/base/layout/catalog_product_prices.xml @@ -0,0 +1,25 @@ + + + + + + + + + Magento\ConfigurableProduct\Pricing\Render\TierPriceBox + Magento_ConfigurableProduct::product/price/tier_price.phtml + + + Magento\ConfigurableProduct\Pricing\Render\FinalPriceBox + Magento_ConfigurableProduct::product/price/final_price.phtml + + + + + + diff --git a/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml new file mode 100644 index 0000000000000..ab3abad184226 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/final_price.phtml @@ -0,0 +1,60 @@ + + +getPriceType('regular_price'); + +/** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */ +$finalPriceModel = $block->getPriceType('final_price'); +$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; +$schema = ($block->getZone() == 'item_view') ? true : false; +?> +hasSpecialPrice()): ?> + + renderAmount($finalPriceModel->getAmount(), [ + 'display_label' => __('Special Price'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ]); ?> + + + renderAmount($priceModel->getAmount(), [ + 'display_label' => __('Regular Price'), + 'price_id' => $block->getPriceId('old-price-' . $idSuffix), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ]); ?> + + + renderAmount($finalPriceModel->getAmount(), [ + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ]); ?> + + +showMinimalPrice()): ?> + getUseLinkForAsLowAs()):?> + + renderAmountMinimal(); ?> + + + + renderAmountMinimal(); ?> + + + diff --git a/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/tier_price.phtml b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/tier_price.phtml new file mode 100644 index 0000000000000..ace120bd13eeb --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/base/templates/product/price/tier_price.phtml @@ -0,0 +1,26 @@ + + +
    diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml index d8f6ae86bd32a..302e246502433 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml index bd61a5d5db520..a73350bd95db6 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_configure_type_configurable.xml @@ -1,11 +1,14 @@ + + + diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml index 9d22b2a65cc2e..9577f947a7a48 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml index 0993cbf80770f..e861caa27aa2d 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/requirejs-config.js b/app/code/Magento/ConfigurableProduct/view/frontend/requirejs-config.js index 8794db668f40b..58b294fe7face 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/requirejs-config.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -9,4 +9,4 @@ var config = { configurable: 'Magento_ConfigurableProduct/js/configurable' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/templates/js/components.phtml b/app/code/Magento/ConfigurableProduct/view/frontend/templates/js/components.phtml index e490a6aa04923..bdcb2e9bf7747 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/templates/js/components.phtml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/templates/js/components.phtml @@ -1,6 +1,6 @@ decorateArray($block->getAllowAttributes()); "#product_addtocart_form": { "configurable": { "spConfig": getJsonConfig() ?>, - "onlyMainImg": getVar('change_only_base_image', 'Magento_ConfigurableProduct') ?: 'false'; ?> + "gallerySwitchStrategy": "getVar('gallery_switch_strategy', + 'Magento_ConfigurableProduct') ?: 'replace'; ?>" } } } diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js new file mode 100644 index 0000000000000..7316f7b75e8be --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable-customer-data.js @@ -0,0 +1,28 @@ +require([ + 'jquery', + 'Magento_ConfigurableProduct/js/options-updater' +], function ($, Updater) { + 'use strict'; + + var selectors = { + formSelector: '#product_addtocart_form' + }, + configurableWidgetName = 'mageConfigurable', + widgetInitEvent = 'configurable.initialized', + + /** + * Sets all configurable attribute's selected values + */ + updateConfigurableOptions = function () { + var configurableWidget = $(selectors.formSelector).data(configurableWidgetName); + + if (!configurableWidget) { + return; + } + configurableWidget.options.values = this.productOptions || {}; + configurableWidget._configureForValues(); + }, + updater = new Updater(widgetInitEvent, updateConfigurableOptions); + + updater.listen(); +}); diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js index d38e2760f1dc7..a97b8928ff1bd 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ @@ -7,11 +7,12 @@ define([ 'jquery', 'underscore', 'mage/template', + 'mage/translate', 'priceUtils', 'priceBox', 'jquery/ui', 'jquery/jquery.parsequery' -], function ($, _, mageTemplate) { +], function ($, _, mageTemplate, $t, priceUtils) { 'use strict'; $.widget('mage.configurable', { @@ -28,7 +29,20 @@ define([ '<% } %>', mediaGallerySelector: '[data-gallery-role=gallery-placeholder]', mediaGalleryInitial: null, - onlyMainImg: false + slyOldPriceSelector: '.sly-old-price', + + /** + * Defines the mechanism of how images of a gallery should be + * updated when user switches between configurations of a product. + * + * As for now value of this option can be either 'replace' or 'prepend'. + * + * @type {String} + */ + gallerySwitchStrategy: 'replace', + tierPriceTemplateSelector: '#tier-prices-template', + tierPriceBlockSelector: '[data-role="tier-price-block"]', + tierPriceTemplate: '' }, /** @@ -53,6 +67,8 @@ define([ // Setup/configure values to inputs this._configureForValues(); + + $(this.element).trigger('configurable.initialized'); }, /** @@ -72,6 +88,7 @@ define([ options.priceFormat = priceBoxOptions.priceFormat; } options.optionTemplate = mageTemplate(options.optionTemplate); + options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html(); options.settings = options.spConfig.containerId ? $(options.spConfig.containerId).find(options.superSelector) : @@ -82,10 +99,10 @@ define([ this.inputSimpleProduct = this.element.find(options.selectSimpleProduct); - gallery.on('gallery:loaded', function () { - var galleryObject = gallery.data('gallery'); - options.mediaGalleryInitial = galleryObject.returnCurrentImages(); - }); + gallery.data('gallery') ? + this._onGalleryLoaded(gallery) : + gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery)); + }, /** @@ -246,6 +263,8 @@ define([ this._resetChildren(element); } this._reloadPrice(); + this._displayRegularPriceBlock(this.simpleProduct); + this._displayTierPriceBlock(this.simpleProduct); this._changeProductImage(); }, @@ -255,46 +274,33 @@ define([ */ _changeProductImage: function () { var images, - initialImages = $.extend(true, [], this.options.mediaGalleryInitial), + initialImages = this.options.mediaGalleryInitial, galleryObject = $(this.options.mediaGallerySelector).data('gallery'); - if (this.options.spConfig.images[this.simpleProduct]) { - images = $.extend(true, [], this.options.spConfig.images[this.simpleProduct]); + if (!galleryObject) { + return; } - function updateGallery(imagesArr) { - var imgToUpdate, - mainImg; + images = this.options.spConfig.images[this.simpleProduct]; - mainImg = imagesArr.filter(function (img) { - return img.isMain; - }); + if (images) { + if (this.options.gallerySwitchStrategy === 'prepend') { + images = images.concat(initialImages); + } - imgToUpdate = mainImg.length ? mainImg[0] : imagesArr[0]; - galleryObject.updateDataByIndex(0, imgToUpdate); - galleryObject.seek(1); - } + images = $.extend(true, [], images); - if (galleryObject) { - if (images) { - images.map(function (img) { - img.type = 'image'; - }); + images.forEach(function (img) { + img.type = 'image'; + }); - if (this.options.onlyMainImg) { - updateGallery(images); - } else { - galleryObject.updateData(images) - } - } else { - if (this.options.onlyMainImg) { - updateGallery(initialImages); - } else { - galleryObject.updateData(this.options.mediaGalleryInitial); - $(this.options.mediaGallerySelector).AddFotoramaVideoEvents(); - } - } + galleryObject.updateData(images); + } else { + galleryObject.updateData(initialImages); + $(this.options.mediaGallerySelector).AddFotoramaVideoEvents(); } + + galleryObject.first(); }, /** @@ -442,7 +448,7 @@ define([ }, /** - * Returns pracies for configured products + * Returns prices for configured products * * @param {*} config - Products configuration * @returns {*} @@ -485,8 +491,60 @@ define([ undefined : _.first(config.allowedProducts); - } + }, + /** + * Show or hide regular price block + * + * @param {*} optionId + * @private + */ + _displayRegularPriceBlock: function (optionId) { + if (typeof optionId != 'undefined' + && this.options.spConfig.optionPrices[optionId].oldPrice.amount + != this.options.spConfig.optionPrices[optionId].finalPrice.amount + ) { + $(this.options.slyOldPriceSelector).show(); + } else { + $(this.options.slyOldPriceSelector).hide(); + } + }, + + /** + * Callback which fired after gallery gets initialized. + * + * @param {HTMLElement} element - DOM element associated with gallery. + */ + _onGalleryLoaded: function (element) { + var galleryObject = element.data('gallery'); + + this.options.mediaGalleryInitial = galleryObject.returnCurrentImages(); + }, + + /** + * Show or hide tier price block + * + * @param {*} optionId + * @private + */ + _displayTierPriceBlock: function (optionId) { + if (typeof optionId != 'undefined' && + this.options.spConfig.optionPrices[optionId].tierPrices != [] + ) { + var options = this.options.spConfig.optionPrices[optionId]; + if (this.options.tierPriceTemplate) { + var tierPriceHtml = mageTemplate(this.options.tierPriceTemplate, { + 'tierPrices': options.tierPrices, + '$t': $t, + 'currencyFormat': this.options.spConfig.currencyFormat, + 'priceUtils': priceUtils + }); + $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show(); + } + } else { + $(this.options.tierPriceBlockSelector).hide(); + } + } }); return $.mage.configurable; diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js new file mode 100644 index 0000000000000..64aefc27dc080 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/view/frontend/web/js/options-updater.js @@ -0,0 +1,77 @@ +define([ + 'jquery', + 'Magento_Customer/js/customer-data' +], function ($, customerData) { + 'use strict'; + + var selectors = { + formSelector: '#product_addtocart_form', + productIdSelector: '#product_addtocart_form [name="product"]' + }, + cartData = customerData.get('cart'), + productId = $(selectors.productIdSelector).val(), + + /** + * set productOptions according to cart data from customer-data + * + * @param {Object} data - cart data from customer-data + * @returns {Boolean} - whether the new options differ from previous + */ + setProductOptions = function (data) { + var changedProductOptions; + + if (!(data && data.items && data.items.length && productId)) { + return false; + } + changedProductOptions = data.items.find(function (item) { + return item['product_id'] === productId; + }); + changedProductOptions = changedProductOptions && changedProductOptions.options && + changedProductOptions.options.reduce(function (obj, val) { + obj[val['option_id']] = val['option_value']; + + return obj; + }, {}); + + if (JSON.stringify(this.productOptions || {}) === JSON.stringify(changedProductOptions || {})) { + return false; + } + + this.productOptions = changedProductOptions; + + return true; + }, + + /** + * Listens to update of cart data or options initialization and update selected option according to customer data + * + */ + listen = function () { + cartData.subscribe(function (updateCartData) { + if (this.setProductOptions(updateCartData)) { + this.updateOptions(); + } + }.bind(this)); + $(selectors.formSelector).on(this.eventName, function () { + this.setProductOptions(cartData()); + this.updateOptions(); + }.bind(this)); + }, + + /** + * Updater constructor function + * + */ + Updater = function (eventName, updateOptionsCallback) { + if (this instanceof Updater) { + this.eventName = eventName; + this.updateOptions = updateOptionsCallback; + this.productOptions = {}; + } + }; + + Updater.prototype.setProductOptions = setProductOptions; + Updater.prototype.listen = listen; + + return Updater; +}); diff --git a/app/code/Magento/Contact/Block/ContactForm.php b/app/code/Magento/Contact/Block/ContactForm.php index 58480f8412f85..f2263ecabb955 100644 --- a/app/code/Magento/Contact/Block/ContactForm.php +++ b/app/code/Magento/Contact/Block/ContactForm.php @@ -1,6 +1,6 @@ _view->loadLayout(); - $this->_view->renderLayout(); + return $this->resultFactory->create(ResultFactory::TYPE_PAGE); } } diff --git a/app/code/Magento/Contact/Controller/Index/Post.php b/app/code/Magento/Contact/Controller/Index/Post.php index 5e7cf615c0deb..9ad831befd06f 100644 --- a/app/code/Magento/Contact/Controller/Index/Post.php +++ b/app/code/Magento/Contact/Controller/Index/Post.php @@ -1,7 +1,7 @@ getMock( \Magento\Framework\App\Action\Context::class, - ['getRequest', 'getResponse', 'getView', 'getUrl'], + ['getRequest', 'getResponse', 'getResultFactory', 'getUrl'], [], '', false @@ -67,8 +70,8 @@ protected function setUp() $this->getMockForAbstractClass(\Magento\Framework\App\ResponseInterface::class, [], '', false) )); - $this->_view = $this->getMock( - \Magento\Framework\App\ViewInterface::class, + $this->resultFactory = $this->getMock( + ResultFactory::class, [], [], '', @@ -76,8 +79,8 @@ protected function setUp() ); $context->expects($this->once()) - ->method('getView') - ->will($this->returnValue($this->_view)); + ->method('getResultFactory') + ->will($this->returnValue($this->resultFactory)); $this->_controller = new \Magento\Contact\Controller\Index\Index( $context, @@ -90,12 +93,12 @@ protected function setUp() public function testExecute() { - $this->_view->expects($this->once()) - ->method('loadLayout'); - - $this->_view->expects($this->once()) - ->method('renderLayout'); + $resultStub = $this->getMockForAbstractClass(ResultInterface::class); + $this->resultFactory->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_PAGE) + ->willReturn($resultStub); - $this->_controller->execute(); + $this->assertSame($resultStub, $this->_controller->execute()); } } diff --git a/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php b/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php index 542e4f4087100..a65302733ddff 100644 --- a/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php +++ b/app/code/Magento/Contact/Test/Unit/Controller/Index/PostTest.php @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/etc/adminhtml/system.xml b/app/code/Magento/Contact/etc/adminhtml/system.xml index ca1ced83457d4..6d39846019a36 100644 --- a/app/code/Magento/Contact/etc/adminhtml/system.xml +++ b/app/code/Magento/Contact/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/etc/config.xml b/app/code/Magento/Contact/etc/config.xml index c40b752cf17c4..3a3e3460585b9 100644 --- a/app/code/Magento/Contact/etc/config.xml +++ b/app/code/Magento/Contact/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/etc/di.xml b/app/code/Magento/Contact/etc/di.xml new file mode 100644 index 0000000000000..0800e42b0ec0c --- /dev/null +++ b/app/code/Magento/Contact/etc/di.xml @@ -0,0 +1,16 @@ + + + + + + + 1 + + + + diff --git a/app/code/Magento/Contact/etc/email_templates.xml b/app/code/Magento/Contact/etc/email_templates.xml index 17bcfeb0d18a5..be2cf76d5911b 100644 --- a/app/code/Magento/Contact/etc/email_templates.xml +++ b/app/code/Magento/Contact/etc/email_templates.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/etc/frontend/di.xml b/app/code/Magento/Contact/etc/frontend/di.xml index d376dca8c834d..b520c9f0e865d 100644 --- a/app/code/Magento/Contact/etc/frontend/di.xml +++ b/app/code/Magento/Contact/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/etc/frontend/page_types.xml b/app/code/Magento/Contact/etc/frontend/page_types.xml index bdf9f108ba355..a6f630d892114 100644 --- a/app/code/Magento/Contact/etc/frontend/page_types.xml +++ b/app/code/Magento/Contact/etc/frontend/page_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/etc/frontend/routes.xml b/app/code/Magento/Contact/etc/frontend/routes.xml index ab07f5492bdbf..ba548c605b71b 100644 --- a/app/code/Magento/Contact/etc/frontend/routes.xml +++ b/app/code/Magento/Contact/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Contact/etc/module.xml b/app/code/Magento/Contact/etc/module.xml index 837b37efec72a..ea6c3d05c692c 100644 --- a/app/code/Magento/Contact/etc/module.xml +++ b/app/code/Magento/Contact/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/registration.php b/app/code/Magento/Contact/registration.php index b7e0223259d3b..6d3f8dc31a95d 100644 --- a/app/code/Magento/Contact/registration.php +++ b/app/code/Magento/Contact/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Contact/view/frontend/layout/contact_index_index.xml b/app/code/Magento/Contact/view/frontend/layout/contact_index_index.xml index ff22911fc0e75..740647609b195 100644 --- a/app/code/Magento/Contact/view/frontend/layout/contact_index_index.xml +++ b/app/code/Magento/Contact/view/frontend/layout/contact_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/view/frontend/layout/default.xml b/app/code/Magento/Contact/view/frontend/layout/default.xml index 6eb2f280e164d..a97cf0ddc64e0 100644 --- a/app/code/Magento/Contact/view/frontend/layout/default.xml +++ b/app/code/Magento/Contact/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Contact/view/frontend/templates/form.phtml b/app/code/Magento/Contact/view/frontend/templates/form.phtml index aa8d69753890f..5380deea65ec7 100644 --- a/app/code/Magento/Contact/view/frontend/templates/form.phtml +++ b/app/code/Magento/Contact/view/frontend/templates/form.phtml @@ -1,44 +1,43 @@ -
    -
    -
    + escapeHtml(__('Write Us')) ?>
    +
    escapeHtml(__('Jot us a note and we’ll get back to you as quickly as possible.')) ?>
    - +
    - +
    - +
    - +
    - +
    - +
    getChildHtml('form.additional.info'); ?> @@ -46,8 +45,8 @@
    -
    diff --git a/app/code/Magento/Cookie/Block/Html/Notices.php b/app/code/Magento/Cookie/Block/Html/Notices.php index 907f32ef26365..3624296560897 100644 --- a/app/code/Magento/Cookie/Block/Html/Notices.php +++ b/app/code/Magento/Cookie/Block/Html/Notices.php @@ -1,6 +1,6 @@ $this->getUrl('cookie/index/noCookies/'), 'triggers' => $this->getTriggers()]; + $params = [ + 'noCookieUrl' => $this->escapeUrl($this->getUrl('cookie/index/noCookies/')), + 'triggers' => $this->escapeHtml($this->getTriggers()) + ]; return json_encode($params); } } diff --git a/app/code/Magento/Cookie/Controller/Index/NoCookies.php b/app/code/Magento/Cookie/Controller/Index/NoCookies.php index bb91ccc917c87..9301a4656427c 100644 --- a/app/code/Magento/Cookie/Controller/Index/NoCookies.php +++ b/app/code/Magento/Cookie/Controller/Index/NoCookies.php @@ -1,7 +1,7 @@ _getAcceptedSaveCookiesWebsites(); - $acceptedSaveCookiesWebsites[$this->_website->getId()] = 1; + $acceptedSaveCookiesWebsites[(int)$this->_website->getId()] = 1; return json_encode($acceptedSaveCookiesWebsites); } diff --git a/app/code/Magento/Cookie/Model/Config/Backend/Cookie.php b/app/code/Magento/Cookie/Model/Config/Backend/Cookie.php index 86791bc60b61b..82b25a55862a7 100644 --- a/app/code/Magento/Cookie/Model/Config/Backend/Cookie.php +++ b/app/code/Magento/Cookie/Model/Config/Backend/Cookie.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Cookie/etc/config.xml b/app/code/Magento/Cookie/etc/config.xml index f50e5fea8facd..4266c755f7737 100644 --- a/app/code/Magento/Cookie/etc/config.xml +++ b/app/code/Magento/Cookie/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Cookie/etc/di.xml b/app/code/Magento/Cookie/etc/di.xml index 0cd62d0632f37..73e5dacb9b2fe 100644 --- a/app/code/Magento/Cookie/etc/di.xml +++ b/app/code/Magento/Cookie/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Cookie/etc/frontend/routes.xml b/app/code/Magento/Cookie/etc/frontend/routes.xml index 70ea487ab5b16..ca903f9d58e5b 100644 --- a/app/code/Magento/Cookie/etc/frontend/routes.xml +++ b/app/code/Magento/Cookie/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Cookie/etc/module.xml b/app/code/Magento/Cookie/etc/module.xml index 0efe82649693a..75b6e7bad6df0 100644 --- a/app/code/Magento/Cookie/etc/module.xml +++ b/app/code/Magento/Cookie/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Cookie/registration.php b/app/code/Magento/Cookie/registration.php index ab3fb6ac73e3f..696427c020dc3 100644 --- a/app/code/Magento/Cookie/registration.php +++ b/app/code/Magento/Cookie/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Cookie/view/frontend/requirejs-config.js b/app/code/Magento/Cookie/view/frontend/requirejs-config.js index 7c90d480ebdfc..680ca42ebd11d 100644 --- a/app/code/Magento/Cookie/view/frontend/requirejs-config.js +++ b/app/code/Magento/Cookie/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -10,4 +10,4 @@ var config = { cookieNotices: 'Magento_Cookie/js/notices' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Cookie/view/frontend/templates/html/notices.phtml b/app/code/Magento/Cookie/view/frontend/templates/html/notices.phtml index cbf1d3ad2b231..741d88df1e4b7 100644 --- a/app/code/Magento/Cookie/view/frontend/templates/html/notices.phtml +++ b/app/code/Magento/Cookie/view/frontend/templates/html/notices.phtml @@ -1,6 +1,6 @@ helper(\Magento\Cookie\Helper\Cookie::class)->isUserNotAllowSaveCookie()): ?> - diff --git a/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rates.phtml b/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rates.phtml index 20e36a1d0ce80..e6b0635b2e292 100644 --- a/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rates.phtml +++ b/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rates.phtml @@ -1,6 +1,6 @@ $this->isAutocompleteEnabled(), - 'customerRegisterUrl' => $this->getCustomerRegisterUrlUrl(), - 'customerForgotPasswordUrl' => $this->getCustomerForgotPasswordUrl(), - 'baseUrl' => $this->getBaseUrl() + 'autocomplete' => $this->escapeHtml($this->isAutocompleteEnabled()), + 'customerRegisterUrl' => $this->escapeUrl($this->getCustomerRegisterUrlUrl()), + 'customerForgotPasswordUrl' => $this->escapeUrl($this->getCustomerForgotPasswordUrl()), + 'baseUrl' => $this->escapeUrl($this->getBaseUrl()) ]; } diff --git a/app/code/Magento/Customer/Block/Account/AuthorizationLink.php b/app/code/Magento/Customer/Block/Account/AuthorizationLink.php index f2e2f1d0bd77f..0b5b3ebac6eba 100644 --- a/app/code/Magento/Customer/Block/Account/AuthorizationLink.php +++ b/app/code/Magento/Customer/Block/Account/AuthorizationLink.php @@ -1,18 +1,19 @@ httpContext->getValue(Context::CONTEXT_AUTH); } + + /** + * {@inheritdoc} + */ + public function getSortOrder() + { + return $this->getData(self::SORT_ORDER); + } } diff --git a/app/code/Magento/Customer/Block/Account/Customer.php b/app/code/Magento/Customer/Block/Account/Customer.php index 5ca6f3b224522..88ebe8e541c92 100644 --- a/app/code/Magento/Customer/Block/Account/Customer.php +++ b/app/code/Magento/Customer/Block/Account/Customer.php @@ -1,6 +1,6 @@ getData(self::SORT_ORDER); + } +} diff --git a/app/code/Magento/Customer/Block/Account/Forgotpassword.php b/app/code/Magento/Customer/Block/Account/Forgotpassword.php index b70c5cd672c52..93936bd5ee7d5 100644 --- a/app/code/Magento/Customer/Block/Account/Forgotpassword.php +++ b/app/code/Magento/Customer/Block/Account/Forgotpassword.php @@ -1,6 +1,6 @@ _customerUrl->getAccountUrl(); } + + /** + * {@inheritdoc} + */ + public function getSortOrder() + { + return $this->getData(self::SORT_ORDER); + } } diff --git a/app/code/Magento/Customer/Block/Account/Navigation.php b/app/code/Magento/Customer/Block/Account/Navigation.php new file mode 100644 index 0000000000000..1eb7ef07bd1ec --- /dev/null +++ b/app/code/Magento/Customer/Block/Account/Navigation.php @@ -0,0 +1,47 @@ +_layout->getChildBlocks($this->getNameInLayout()); + $sortableLink = []; + foreach ($links as $key => $link) { + if ($link instanceof SortLinkInterface) { + $sortableLink[] = $link; + unset($links[$key]); + } + } + + usort($sortableLink, [$this, "compare"]); + return array_merge($sortableLink, $links); + } + + /** + * Compare sortOrder in links. + * + * @param SortLinkInterface $firstLink + * @param SortLinkInterface $secondLink + * @return int + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + */ + private function compare(SortLinkInterface $firstLink, SortLinkInterface $secondLink) + { + return ($firstLink->getSortOrder() < $secondLink->getSortOrder()); + } +} diff --git a/app/code/Magento/Customer/Block/Account/RegisterLink.php b/app/code/Magento/Customer/Block/Account/RegisterLink.php index f08132bc2cfa2..17bdcc26d6f59 100644 --- a/app/code/Magento/Customer/Block/Account/RegisterLink.php +++ b/app/code/Magento/Customer/Block/Account/RegisterLink.php @@ -1,6 +1,6 @@ getData(self::SORT_ORDER); + } +} diff --git a/app/code/Magento/Customer/Block/Account/SortLinkInterface.php b/app/code/Magento/Customer/Block/Account/SortLinkInterface.php new file mode 100644 index 0000000000000..96636f7ab1dc6 --- /dev/null +++ b/app/code/Magento/Customer/Block/Account/SortLinkInterface.php @@ -0,0 +1,27 @@ +messageManager->addError($e->getMessage()); } catch (UserLockedException $e) { $message = __( - 'The account is locked. Please wait and try again or contact %1.', - $this->getScopeConfig()->getValue('contact/email/recipient_email') + 'You did not sign in correctly or your account is temporarily disabled.' ); $this->session->logout(); $this->session->start(); @@ -195,22 +189,6 @@ public function execute() return $resultRedirect->setPath('*/*/edit'); } - /** - * Get scope config - * - * @return ScopeConfigInterface - */ - private function getScopeConfig() - { - if (!($this->scopeConfig instanceof \Magento\Framework\App\Config\ScopeConfigInterface)) { - return ObjectManager::getInstance()->get( - \Magento\Framework\App\Config\ScopeConfigInterface::class - ); - } else { - return $this->scopeConfig; - } - } - /** * Account editing action completed successfully event * diff --git a/app/code/Magento/Customer/Controller/Account/ForgotPassword.php b/app/code/Magento/Customer/Controller/Account/ForgotPassword.php index 7cb5a4ce7fa01..0c7cae6e1ae1d 100644 --- a/app/code/Magento/Customer/Controller/Account/ForgotPassword.php +++ b/app/code/Magento/Customer/Controller/Account/ForgotPassword.php @@ -1,7 +1,7 @@ session->setUsername($login['username']); } catch (UserLockedException $e) { $message = __( - 'The account is locked. Please wait and try again or contact %1.', - $this->getScopeConfig()->getValue('contact/email/recipient_email') + 'You did not sign in correctly or your account is temporarily disabled.' ); $this->messageManager->addError($message); $this->session->setUsername($login['username']); } catch (AuthenticationException $e) { - $message = __('Invalid login or password.'); + $message = __('You did not sign in correctly or your account is temporarily disabled.'); $this->messageManager->addError($message); $this->session->setUsername($login['username']); } catch (LocalizedException $e) { diff --git a/app/code/Magento/Customer/Controller/Account/Logout.php b/app/code/Magento/Customer/Controller/Account/Logout.php index 1f0dd1057e73d..0c182b0da4fe3 100644 --- a/app/code/Magento/Customer/Controller/Account/Logout.php +++ b/app/code/Magento/Customer/Controller/Account/Logout.php @@ -1,7 +1,7 @@ getMessage(); } $this->_addSessionErrorMessages($messages); + } catch (SecurityViolationException $exception) { + $this->messageManager->addErrorMessage($exception->getMessage()); } catch (\Exception $exception) { $this->messageManager->addException( $exception, diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php index 77bf7af2a4031..59518597cc1c5 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php @@ -1,6 +1,6 @@ getMetadataForm($entityType, $formCode, $scope); $formData = $metadataForm->extractData($this->getRequest(), $scope); + $formData = $metadataForm->compactData($formData); // Initialize additional attributes /** @var \Magento\Framework\DataObject $object */ @@ -81,11 +82,6 @@ protected function _extractData( $formData[$attributeCode] = isset($requestData[$attributeCode]) ? $requestData[$attributeCode] : false; } - $result = $metadataForm->compactData($formData); - - // Re-initialize additional attributes - $formData = array_replace($formData, $result); - // Unset unused attributes $formAttributes = $metadataForm->getAttributes(); foreach ($formAttributes as $attribute) { diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php index 2c9be2d013bf6..f353f35994bd0 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php @@ -1,6 +1,6 @@ resultJsonFactory = $resultJsonFactory; $this->sectionIdentifier = $sectionIdentifier; $this->sectionPool = $sectionPool; + $this->escaper = $escaper ?: $this->_objectManager->get(\Magento\Framework\Escaper::class); } /** - * @return \Magento\Framework\Controller\Result\Json|\Magento\Framework\Controller\Result\Redirect + * @return \Magento\Framework\Controller\Result\Json */ public function execute() { @@ -60,7 +69,7 @@ public function execute() $sectionNames = $sectionNames ? array_unique(\explode(',', $sectionNames)) : null; $updateSectionId = $this->getRequest()->getParam('update_section_id'); - if ('false' == $updateSectionId) { + if ('false' === $updateSectionId) { $updateSectionId = false; } $response = $this->sectionPool->getSectionsData($sectionNames, (bool)$updateSectionId); @@ -70,7 +79,7 @@ public function execute() \Zend\Http\AbstractMessage::VERSION_11, 'Bad Request' ); - $response = ['message' => $e->getMessage()]; + $response = ['message' => $this->escaper->escapeHtml($e->getMessage())]; } return $resultJson->setData($response); diff --git a/app/code/Magento/Customer/CustomerData/Customer.php b/app/code/Magento/Customer/CustomerData/Customer.php index 6b7d0e15f7622..7a8b982ecdc6d 100644 --- a/app/code/Magento/Customer/CustomerData/Customer.php +++ b/app/code/Magento/Customer/CustomerData/Customer.php @@ -1,6 +1,6 @@ request = $request; $this->session = $customerSession; @@ -95,6 +104,7 @@ public function __construct( $this->urlDecoder = $urlDecoder; $this->customerUrl = $customerUrl; $this->resultFactory = $resultFactory; + $this->hostChecker = $hostChecker ?: ObjectManager::getInstance()->get(HostChecker::class); } /** @@ -196,7 +206,7 @@ protected function processLoggedCustomer() $referer = $this->request->getParam(CustomerUrl::REFERER_QUERY_PARAM_NAME); if ($referer) { $referer = $this->urlDecoder->decode($referer); - if ($this->url->isOwnOriginUrl()) { + if ($this->hostChecker->isOwnOrigin($referer)) { $this->applyRedirect($referer); } } diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 56125575e7ec5..75cc525b3bd72 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -1,6 +1,6 @@ getFirstname(), 'NotEmpty')) { - $errors[] = __('Please enter the first name.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'firstname']); } if (!\Zend_Validate::is($this->getLastname(), 'NotEmpty')) { - $errors[] = __('Please enter the last name.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'lastname']); } if (!\Zend_Validate::is($this->getStreetLine(1), 'NotEmpty')) { - $errors[] = __('Please enter the street.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'street']); } if (!\Zend_Validate::is($this->getCity(), 'NotEmpty')) { - $errors[] = __('Please enter the city.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'city']); } if (!\Zend_Validate::is($this->getTelephone(), 'NotEmpty')) { - $errors[] = __('Please enter the phone number.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'telephone']); + } $_havingOptionalZip = $this->_directoryData->getCountriesWithOptionalZip(); @@ -590,11 +593,11 @@ public function validate() 'NotEmpty' ) ) { - $errors[] = __('Please enter the zip/postal code.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'postcode']); } if (!\Zend_Validate::is($this->getCountryId(), 'NotEmpty')) { - $errors[] = __('Please enter the country.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'countryId']); } if ($this->getCountryModel()->getRegionCollection()->getSize() && !\Zend_Validate::is( @@ -604,7 +607,7 @@ public function validate() $this->getCountryId() ) ) { - $errors[] = __('Please enter the state/province.'); + $errors[] = __('%fieldName is a required field.', ['fieldName' => 'regionId']); } if (empty($errors) || $this->getShouldIgnoreValidation()) { diff --git a/app/code/Magento/Customer/Model/Address/AddressModelInterface.php b/app/code/Magento/Customer/Model/Address/AddressModelInterface.php index 3e3d7267128c9..f930c4c746aab 100644 --- a/app/code/Magento/Customer/Model/Address/AddressModelInterface.php +++ b/app/code/Magento/Customer/Model/Address/AddressModelInterface.php @@ -1,6 +1,6 @@ + * Customer address configuration */ class Config extends ConfigData { @@ -23,7 +22,7 @@ class Config extends ConfigData const DEFAULT_ADDRESS_FORMAT = 'oneline'; /** - * Customer Address Templates per store + * Customer address templates per store * * @var array */ @@ -37,8 +36,7 @@ class Config extends ConfigData protected $_store = null; /** - * Default types per store - * Using for invalid code + * Default types per store, used for invalid code * * @var array */ @@ -60,12 +58,15 @@ class Config extends ConfigData protected $_scopeConfig; /** - * @param \Magento\Customer\Model\Address\Config\Reader $reader + * Constructor + * + * @param Config\Reader $reader * @param \Magento\Framework\Config\CacheInterface $cache * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Customer\Helper\Address $addressHelper * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig - * @param string $cacheId + * @param string|null $cacheId + * @param SerializerInterface|null $serializer */ public function __construct( \Magento\Customer\Model\Address\Config\Reader $reader, @@ -73,9 +74,10 @@ public function __construct( \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Customer\Helper\Address $addressHelper, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - $cacheId = 'address_format' + $cacheId = 'address_format', + SerializerInterface $serializer = null ) { - parent::__construct($reader, $cache, $cacheId); + parent::__construct($reader, $cache, $cacheId, $serializer); $this->_storeManager = $storeManager; $this->_addressHelper = $addressHelper; $this->_scopeConfig = $scopeConfig; diff --git a/app/code/Magento/Customer/Model/Address/Config/Converter.php b/app/code/Magento/Customer/Model/Address/Config/Converter.php index 5803779c8e651..cbf9ece8c5fb0 100644 --- a/app/code/Magento/Customer/Model/Address/Config/Converter.php +++ b/app/code/Magento/Customer/Model/Address/Config/Converter.php @@ -2,7 +2,7 @@ /** * Converter of customer address format configuration from \DOMDocument to array * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Model\Address\Config; diff --git a/app/code/Magento/Customer/Model/Address/Config/Reader.php b/app/code/Magento/Customer/Model/Address/Config/Reader.php index 56ba5658e7666..623dd8b78d244 100644 --- a/app/code/Magento/Customer/Model/Address/Config/Reader.php +++ b/app/code/Magento/Customer/Model/Address/Config/Reader.php @@ -2,7 +2,7 @@ /** * Customer address format configuration filesystem loader. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Model\Address\Config; diff --git a/app/code/Magento/Customer/Model/Address/Config/SchemaLocator.php b/app/code/Magento/Customer/Model/Address/Config/SchemaLocator.php index e5db3232f68e1..e48c7985e8236 100644 --- a/app/code/Magento/Customer/Model/Address/Config/SchemaLocator.php +++ b/app/code/Magento/Customer/Model/Address/Config/SchemaLocator.php @@ -2,7 +2,7 @@ /** * Customer address format configuration schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Model\Address\Config; diff --git a/app/code/Magento/Customer/Model/Address/CustomAttributeList.php b/app/code/Magento/Customer/Model/Address/CustomAttributeList.php index f83b37c2a814d..d0fe7c8dbd43b 100644 --- a/app/code/Magento/Customer/Model/Address/CustomAttributeList.php +++ b/app/code/Magento/Customer/Model/Address/CustomAttributeList.php @@ -1,6 +1,6 @@ _groupManagement = $groupManagement; $this->_converter = $converter; + $this->groupSourceLoggedInOnly = $groupSourceForLoggedInCustomers + ?: ObjectManager::getInstance()->get(GroupSourceLoggedInOnlyInterface::class); } /** - * @return array + * @inheritdoc */ public function toOptionArray() { if (!$this->_options) { - $groups = $this->_groupManagement->getLoggedInGroups(); - $this->_options = $this->_converter->toOptionArray($groups, 'id', 'code'); + $this->_options = $this->groupSourceLoggedInOnly->toOptionArray(); array_unshift($this->_options, ['value' => '', 'label' => __('-- Please Select --')]); } + return $this->_options; } } diff --git a/app/code/Magento/Customer/Model/Config/Source/Group/Multiselect.php b/app/code/Magento/Customer/Model/Config/Source/Group/Multiselect.php index 708e3243e2699..d2ef514a17e49 100644 --- a/app/code/Magento/Customer/Model/Config/Source/Group/Multiselect.php +++ b/app/code/Magento/Customer/Model/Config/Source/Group/Multiselect.php @@ -1,11 +1,13 @@ _groupManagement = $groupManagement; $this->_converter = $converter; + $this->groupSourceLoggedInOnly = $groupSourceLoggedInOnly + ?: ObjectManager::getInstance()->get(GroupSourceLoggedInOnlyInterface::class); } /** @@ -46,8 +59,7 @@ public function __construct( public function toOptionArray() { if (!$this->_options) { - $groups = $this->_groupManagement->getLoggedInGroups(); - $this->_options = $this->_converter->toOptionArray($groups, 'id', 'code'); + $this->_options = $this->groupSourceLoggedInOnly->toOptionArray(); } return $this->_options; } diff --git a/app/code/Magento/Customer/Model/Context.php b/app/code/Magento/Customer/Model/Context.php index f28882feafef7..8634993e8866b 100644 --- a/app/code/Magento/Customer/Model/Context.php +++ b/app/code/Magento/Customer/Model/Context.php @@ -1,6 +1,6 @@ */ -class Group extends \Magento\Eav\Model\Entity\Attribute\Source\Table +class Group extends \Magento\Eav\Model\Entity\Attribute\Source\Table implements GroupSourceLoggedInOnlyInterface { /** * @var GroupManagementInterface @@ -50,6 +50,7 @@ public function getAllOptions() $groups = $this->_groupManagement->getLoggedInGroups(); $this->_options = $this->_converter->toOptionArray($groups, 'id', 'code'); } + return $this->_options; } } diff --git a/app/code/Magento/Customer/Model/Customer/Attribute/Source/GroupSourceLoggedInOnlyInterface.php b/app/code/Magento/Customer/Model/Customer/Attribute/Source/GroupSourceLoggedInOnlyInterface.php new file mode 100644 index 0000000000000..43c1ebbd1c7dc --- /dev/null +++ b/app/code/Magento/Customer/Model/Customer/Attribute/Source/GroupSourceLoggedInOnlyInterface.php @@ -0,0 +1,14 @@ +getStat($file); $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); - } - - $fileName = $file; - if (strrpos($fileName, '/') !== false) { - $fileName = substr($fileName, strrpos($fileName, '/') + 1); - } - if (!empty($file)) { return [ [ 'file' => $file, 'size' => isset($stat) ? $stat['size'] : 0, 'url' => isset($viewUrl) ? $viewUrl : '', - 'name' => $fileName, + 'name' => basename($file), + 'type' => $fileProcessor->getMimeType($file), ], ]; } + return []; } @@ -292,6 +302,7 @@ protected function getAttributesMeta(Type $entityType) $this->processFrontendInput($attribute, $meta); $code = $attribute->getAttributeCode(); + // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value foreach ($this->metaProperties as $metaName => $origName) { $value = $attribute->getDataUsingMethod($origName); @@ -304,7 +315,12 @@ protected function getAttributesMeta(Type $entityType) } if ($attribute->usesSource()) { - $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + if ($code == AddressInterface::COUNTRY_ID) { + $meta[$code]['arguments']['data']['config']['options'] = $this->getCountryWithWebsiteSource() + ->getAllOptions(); + } else { + $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + } } $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); @@ -315,9 +331,61 @@ protected function getAttributesMeta(Type $entityType) $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); } + + $this->processWebsiteMeta($meta); return $meta; } + /** + * Retrieve Country With Websites Source + * + * @deprecated + * @return CountryWithWebsites + */ + private function getCountryWithWebsiteSource() + { + if (!$this->countryWithWebsiteSource) { + $this->countryWithWebsiteSource = ObjectManager::getInstance()->get(CountryWithWebsites::class); + } + + return $this->countryWithWebsiteSource; + } + + /** + * Retrieve Customer Config Share + * + * @deprecated + * @return \Magento\Customer\Model\Config\Share + */ + private function getShareConfig() + { + if (!$this->shareConfig) { + $this->shareConfig = ObjectManager::getInstance()->get(\Magento\Customer\Model\Config\Share::class); + } + + return $this->shareConfig; + } + + /** + * Add global scope parameter and filter options to website meta + * + * @param array $meta + * @return void + */ + private function processWebsiteMeta(&$meta) + { + if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->getShareConfig()->isGlobalScope()) { + $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; + } + + if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->getShareConfig()->isGlobalScope()) { + $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ]; + } + } + /** * Override file uploader UI component metadata * diff --git a/app/code/Magento/Customer/Model/Customer/Mapper.php b/app/code/Magento/Customer/Model/Customer/Mapper.php index e7671319b00a2..795878e3079f2 100644 --- a/app/code/Magento/Customer/Model/Customer/Mapper.php +++ b/app/code/Magento/Customer/Model/Customer/Mapper.php @@ -1,6 +1,6 @@ cache = $cache; @@ -34,7 +45,7 @@ public function __construct(FrontendInterface $cache) public function add($notificationType, $customerId) { $this->cache->save( - serialize([ + $this->getSerializer()->serialize([ 'customer_id' => $customerId, 'notification_type' => $notificationType ]), @@ -77,4 +88,19 @@ private function getCacheKey($notificationType, $customerId) { return 'notification_' . $notificationType . '_' . $customerId; } + + /** + * Get serializer + * + * @return SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/app/code/Magento/Customer/Model/Customer/Source/Group.php b/app/code/Magento/Customer/Model/Customer/Source/Group.php index 59dc3be52f1e5..17792b98533e1 100644 --- a/app/code/Magento/Customer/Model/Customer/Source/Group.php +++ b/app/code/Magento/Customer/Model/Customer/Source/Group.php @@ -1,16 +1,17 @@ moduleManager->isEnabled('Magento_Customer')) { return []; } - $customerGroups = [ - [ - 'label' => __('ALL GROUPS'), - 'value' => GroupInterface::CUST_GROUP_ALL, - ] + $customerGroups = []; + $customerGroups[] = [ + 'label' => __('ALL GROUPS'), + 'value' => GroupInterface::CUST_GROUP_ALL, ]; - /** @var GroupInterface[] $groups */ + /** @var GroupSearchResultsInterface $groups */ $groups = $this->groupRepository->getList($this->searchCriteriaBuilder->create()); foreach ($groups->getItems() as $group) { $customerGroups[] = [ diff --git a/app/code/Magento/Customer/Model/Customer/Source/GroupSourceInterface.php b/app/code/Magento/Customer/Model/Customer/Source/GroupSourceInterface.php new file mode 100644 index 0000000000000..2bff3665bbb91 --- /dev/null +++ b/app/code/Magento/Customer/Model/Customer/Source/GroupSourceInterface.php @@ -0,0 +1,13 @@ +mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); $this->uploaderFactory = $uploaderFactory; $this->urlBuilder = $urlBuilder; $this->urlEncoder = $urlEncoder; $this->entityTypeCode = $entityTypeCode; + $this->mime = $mime; $this->allowedExtensions = $allowedExtensions; } @@ -107,6 +104,21 @@ public function getStat($fileName) return $result; } + /** + * Retrieve MIME type of requested file + * + * @param string $fileName + * @return string + */ + public function getMimeType($fileName) + { + $filePath = $this->entityTypeCode . '/' . ltrim($fileName, '/'); + $absoluteFilePath = $this->mediaDirectory->getAbsolutePath($filePath); + + $result = $this->mime->getMimeType($absoluteFilePath); + return $result; + } + /** * Check if the file exists * @@ -132,13 +144,13 @@ public function getViewUrl($filePath, $type) { $viewUrl = ''; - if ($this->entityTypeCode == AddressMetadataInterface::ENTITY_TYPE_ADDRESS) { + if ($this->entityTypeCode == \Magento\Customer\Api\AddressMetadataInterface::ENTITY_TYPE_ADDRESS) { $filePath = $this->entityTypeCode . '/' . ltrim($filePath, '/'); - $viewUrl = $this->urlBuilder->getBaseUrl(['_type' => UrlInterface::URL_TYPE_MEDIA]) + $viewUrl = $this->urlBuilder->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_MEDIA]) . $this->mediaDirectory->getRelativePath($filePath); } - if ($this->entityTypeCode == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) { + if ($this->entityTypeCode == \Magento\Customer\Api\CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) { $viewUrl = $this->urlBuilder->getUrl( 'customer/index/viewfile', [$type => $this->urlEncoder->encode(ltrim($filePath, '/'))] @@ -153,11 +165,11 @@ public function getViewUrl($filePath, $type) * * @param string $fileId * @return \string[] - * @throws LocalizedException + * @throws \Magento\Framework\Exception\LocalizedException */ public function saveTemporaryFile($fileId) { - /** @var Uploader $uploader */ + /** @var \Magento\MediaStorage\Model\File\Uploader $uploader */ $uploader = $this->uploaderFactory->create(['fileId' => $fileId]); $uploader->setFilesDispersion(false); $uploader->setFilenamesCaseSensitivity(false); @@ -170,7 +182,9 @@ public function saveTemporaryFile($fileId) $result = $uploader->save($path); if (!$result) { - throw new LocalizedException(__('File can not be saved to the destination folder.')); + throw new \Magento\Framework\Exception\LocalizedException( + __('File can not be saved to the destination folder.') + ); } return $result; @@ -181,28 +195,28 @@ public function saveTemporaryFile($fileId) * * @param string $fileName * @return string - * @throws LocalizedException + * @throws \Magento\Framework\Exception\LocalizedException */ public function moveTemporaryFile($fileName) { $fileName = ltrim($fileName, '/'); - $dispersionPath = Uploader::getDispretionPath($fileName); + $dispersionPath = \Magento\MediaStorage\Model\File\Uploader::getDispretionPath($fileName); $destinationPath = $this->entityTypeCode . $dispersionPath; if (!$this->mediaDirectory->create($destinationPath)) { - throw new LocalizedException( + throw new \Magento\Framework\Exception\LocalizedException( __('Unable to create directory %1.', $destinationPath) ); } if (!$this->mediaDirectory->isWritable($destinationPath)) { - throw new LocalizedException( + throw new \Magento\Framework\Exception\LocalizedException( __('Destination folder is not writable or does not exists.') ); } - $destinationFileName = Uploader::getNewFileName( + $destinationFileName = \Magento\MediaStorage\Model\File\Uploader::getNewFileName( $this->mediaDirectory->getAbsolutePath($destinationPath) . '/' . $fileName ); @@ -212,7 +226,7 @@ public function moveTemporaryFile($fileName) $destinationPath . '/' . $destinationFileName ); } catch (\Exception $e) { - throw new LocalizedException( + throw new \Magento\Framework\Exception\LocalizedException( __('Something went wrong while saving the file.') ); } diff --git a/app/code/Magento/Customer/Model/FileUploader.php b/app/code/Magento/Customer/Model/FileUploader.php index 97dfdafdf7575..d6fb867af7fa6 100644 --- a/app/code/Magento/Customer/Model/FileUploader.php +++ b/app/code/Magento/Customer/Model/FileUploader.php @@ -1,6 +1,6 @@ customerCollection = $collectionFactory->create(); + $this->batchSize = $batchSize; + } + + /** + * {@inheritdoc} + */ + public function getMainTable() + { + return $this->customerCollection->getMainTable(); + } + + /** + * {@inheritdoc} + */ + public function getIdFieldName() + { + return $this->customerCollection->getIdFieldName(); + } + + /** + * {@inheritdoc} + */ + public function addFieldToSelect($fieldName, $alias = null) + { + $this->customerCollection->addFieldToSelect($fieldName, $alias); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getSelect() + { + return $this->customerCollection->getSelect(); + } + + /** + * {@inheritdoc} + */ + public function addFieldToFilter($attribute, $condition = null) + { + $this->customerCollection->addFieldToFilter($attribute, $condition); + return $this; + } + + /** + * @return int + */ + public function count() + { + return $this->customerCollection->getSize(); + } + + /** + * Retrieve an iterator + * + * @return Traversable + */ + public function getIterator() + { + $this->customerCollection->setPageSize($this->batchSize); + $lastPage = $this->customerCollection->getLastPageNumber(); + $pageNumber = 0; + do { + $this->customerCollection->clear(); + $this->customerCollection->setCurPage($pageNumber); + foreach ($this->customerCollection->getItems() as $key => $value) { + yield $key => $value; + } + $pageNumber++; + } while ($pageNumber <= $lastPage); + } +} diff --git a/app/code/Magento/Customer/Model/Layout/DepersonalizePlugin.php b/app/code/Magento/Customer/Model/Layout/DepersonalizePlugin.php index 9ec70096d5806..bc616353c4867 100644 --- a/app/code/Magento/Customer/Model/Layout/DepersonalizePlugin.php +++ b/app/code/Magento/Customer/Model/Layout/DepersonalizePlugin.php @@ -2,7 +2,7 @@ /** * Depersonalize customer session data * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Model\Layout; diff --git a/app/code/Magento/Customer/Model/Log.php b/app/code/Magento/Customer/Model/Log.php index be2be8c3a552d..a2e6a5b0919c7 100644 --- a/app/code/Magento/Customer/Model/Log.php +++ b/app/code/Magento/Customer/Model/Log.php @@ -1,6 +1,6 @@ shareConfig = $share; + $this->storeManager = $storeManager; + } + + /** + * Retrieve all allowed countries or specific by scope depends on customer share setting + * + * @param \Magento\Directory\Model\AllowedCountries $subject + * @param string | null $filter + * @param string $scope + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeGetAllowedCountries( + \Magento\Directory\Model\AllowedCountries $subject, + $scope = ScopeInterface::SCOPE_WEBSITE, + $scopeCode = null + ) { + if ($this->shareConfig->isGlobalScope()) { + //Check if we have shared accounts - than merge all website allowed countries + $scopeCode = array_map(function (WebsiteInterface $website) { + return $website->getId(); + }, $this->storeManager->getWebsites()); + $scope = ScopeInterface::SCOPE_WEBSITES; + } + + return [$scope, $scopeCode]; + } +} diff --git a/app/code/Magento/Customer/Model/Plugin/CustomerAuthorization.php b/app/code/Magento/Customer/Model/Plugin/CustomerAuthorization.php index 971ced8b0373b..e45d292742ad7 100644 --- a/app/code/Magento/Customer/Model/Plugin/CustomerAuthorization.php +++ b/app/code/Magento/Customer/Model/Plugin/CustomerAuthorization.php @@ -1,6 +1,6 @@ _options) { $this->_options = $this->_createCountriesCollection()->loadByStore( - $this->getAttribute()->getStoreId() + $this->getStoreResolver()->getCurrentStoreId() )->toOptionArray(); } return $this->_options; @@ -54,4 +68,18 @@ protected function _createCountriesCollection() { return $this->_countriesFactory->create(); } + + /** + * Retrieve Store Resolver + * @deprecated + * @return StoreResolverInterface + */ + private function getStoreResolver() + { + if (!$this->storeResolver) { + $this->storeResolver = ObjectManager::getInstance()->get(StoreResolverInterface::class); + } + + return $this->storeResolver; + } } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Attribute/Source/CountryWithWebsites.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Attribute/Source/CountryWithWebsites.php new file mode 100644 index 0000000000000..2fb02ee05cabe --- /dev/null +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Attribute/Source/CountryWithWebsites.php @@ -0,0 +1,117 @@ + + */ +namespace Magento\Customer\Model\ResourceModel\Address\Attribute\Source; + +use Magento\Customer\Model\Config\Share; +use Magento\Directory\Model\AllowedCountries; +use Magento\Store\Model\ScopeInterface; + +class CountryWithWebsites extends \Magento\Eav\Model\Entity\Attribute\Source\Table +{ + /** + * @var \Magento\Directory\Model\ResourceModel\Country\CollectionFactory + */ + private $countriesFactory; + + /** + * @var \Magento\Directory\Model\AllowedCountries + */ + private $allowedCountriesReader; + + /** + * @var array + */ + private $options; + + /** + * @var \Magento\Store\Model\StoreManagerInterface + */ + private $storeManager; + + /** + * @var Share + */ + private $shareConfig; + + /** + * CountryWithWebsites constructor. + * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory $attrOptionCollectionFactory + * @param \Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory $attrOptionFactory + * @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countriesFactory + * @param AllowedCountries $allowedCountriesReader + * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param Share $shareConfig + */ + public function __construct( + \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory $attrOptionCollectionFactory, + \Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory $attrOptionFactory, + \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $countriesFactory, + \Magento\Directory\Model\AllowedCountries $allowedCountriesReader, + \Magento\Store\Model\StoreManagerInterface $storeManager, + \Magento\Customer\Model\Config\Share $shareConfig + ) { + $this->countriesFactory = $countriesFactory; + $this->allowedCountriesReader = $allowedCountriesReader; + $this->storeManager = $storeManager; + $this->shareConfig = $shareConfig; + parent::__construct($attrOptionCollectionFactory, $attrOptionFactory); + } + + /** + * Retrieve all options + * + * @return array + */ + public function getAllOptions() + { + if (!$this->options) { + $allowedCountries = []; + $websiteIds = []; + + if (!$this->shareConfig->isGlobalScope()) { + foreach ($this->storeManager->getWebsites() as $website) { + $countries = $this->allowedCountriesReader + ->getAllowedCountries(ScopeInterface::SCOPE_WEBSITE, $website->getId()); + $allowedCountries = array_merge($allowedCountries, $countries); + + foreach ($countries as $countryCode) { + $websiteIds[$countryCode][] = $website->getId(); + } + } + } else { + $allowedCountries = $this->allowedCountriesReader->getAllowedCountries(); + } + + $this->options = $this->createCountriesCollection() + ->addFieldToFilter('country_id', ['in' => $allowedCountries]) + ->toOptionArray(); + + foreach ($this->options as &$option) { + if (isset($websiteIds[$option['value']])) { + $option['website_ids'] = $websiteIds[$option['value']]; + } + } + } + + return $this->options; + } + + /** + * Create Countries Collection with all countries + * + * @return \Magento\Directory\Model\ResourceModel\Country\Collection + */ + private function createCountriesCollection() + { + return $this->countriesFactory->create(); + } +} diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Attribute/Source/Region.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Attribute/Source/Region.php index 7c31248384245..0ab5a7dd0c120 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Attribute/Source/Region.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Attribute/Source/Region.php @@ -1,6 +1,6 @@ updateData($address); } - $inputException = $this->_validate($addressModel); - if ($inputException->wasErrorAdded()) { + $errors = $addressModel->validate(); + if ($errors !== true) { + $inputException = new InputException(); + foreach ($errors as $error) { + $inputException->addError($error); + } throw $inputException; } $addressModel->save(); @@ -255,70 +259,6 @@ public function deleteById($addressId) return true; } - /** - * Validate Customer Addresses attribute values. - * - * @param CustomerAddressModel $customerAddressModel the model to validate - * @return InputException - * - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - private function _validate(CustomerAddressModel $customerAddressModel) - { - $exception = new InputException(); - if ($customerAddressModel->getShouldIgnoreValidation()) { - return $exception; - } - - if (!\Zend_Validate::is($customerAddressModel->getFirstname(), 'NotEmpty')) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'firstname'])); - } - - if (!\Zend_Validate::is($customerAddressModel->getLastname(), 'NotEmpty')) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'lastname'])); - } - - if (!\Zend_Validate::is($customerAddressModel->getStreetLine(1), 'NotEmpty')) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'street'])); - } - - if (!\Zend_Validate::is($customerAddressModel->getCity(), 'NotEmpty')) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'city'])); - } - - if (!\Zend_Validate::is($customerAddressModel->getTelephone(), 'NotEmpty')) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'telephone'])); - } - - $havingOptionalZip = $this->directoryData->getCountriesWithOptionalZip(); - if (!in_array($customerAddressModel->getCountryId(), $havingOptionalZip) - && !\Zend_Validate::is($customerAddressModel->getPostcode(), 'NotEmpty') - ) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'postcode'])); - } - - if (!\Zend_Validate::is($customerAddressModel->getCountryId(), 'NotEmpty')) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'countryId'])); - } - - if ($this->directoryData->isRegionRequired($customerAddressModel->getCountryId())) { - $regionCollection = $customerAddressModel->getCountryModel()->getRegionCollection(); - if (!$regionCollection->count() && empty($customerAddressModel->getRegion())) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'region'])); - } elseif ( - $regionCollection->count() - && !in_array( - $customerAddressModel->getRegionId(), - array_column($regionCollection->getData(), 'region_id') - ) - ) { - $exception->addError(__('%fieldName is a required field.', ['fieldName' => 'regionId'])); - } - } - return $exception; - } - /** * Retrieve collection processor * diff --git a/app/code/Magento/Customer/Model/ResourceModel/Attribute.php b/app/code/Magento/Customer/Model/ResourceModel/Attribute.php index f126b4401069b..2dfe24a351e45 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Attribute.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Attribute.php @@ -1,6 +1,6 @@ getId()) { $prevCustomerData = $this->getById($customer->getId()); + $prevCustomerDataArr = $prevCustomerData->__toArray(); } + /** @var $customer \Magento\Customer\Model\Data\Customer */ + $customerArr = $customer->__toArray(); $customer = $this->imageProcessor->save( $customer, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, @@ -185,6 +189,20 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa $customerModel->setRpToken(null); $customerModel->setRpTokenCreatedAt(null); } + if (!array_key_exists('default_billing', $customerArr) && + null !== $prevCustomerDataArr && + array_key_exists('default_billing', $prevCustomerDataArr) + ) { + $customerModel->setDefaultBilling($prevCustomerDataArr['default_billing']); + } + + if (!array_key_exists('default_shipping', $customerArr) && + null !== $prevCustomerDataArr && + array_key_exists('default_shipping', $prevCustomerDataArr) + ) { + $customerModel->setDefaultShipping($prevCustomerDataArr['default_shipping']); + } + $customerModel->save(); $this->customerRegistry->push($customerModel); $customerId = $customerModel->getId(); diff --git a/app/code/Magento/Customer/Model/ResourceModel/Db/VersionControl/AddressSnapshot.php b/app/code/Magento/Customer/Model/ResourceModel/Db/VersionControl/AddressSnapshot.php index 27f335d125be5..192a9ec4fe9b0 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Db/VersionControl/AddressSnapshot.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Db/VersionControl/AddressSnapshot.php @@ -1,6 +1,6 @@ setCode(substr($group->getCode(), 0, $group::GROUP_CODE_MAX_LENGTH)); return parent::_beforeSave($group); } + + /** + * {@inheritdoc} + */ + protected function _afterSave(\Magento\Framework\Model\AbstractModel $object) + { + if ($object->getId() == \Magento\Customer\Model\Group::CUST_GROUP_ALL) { + $this->skipReservedId($object); + } + + return $this; + } + + /** + * Here we do not allow to save systems reserved ID. + * + * @param \Magento\Framework\Model\AbstractModel $object + * @throws \Magento\Framework\Exception\LocalizedException + * @return void + */ + private function skipReservedId(\Magento\Framework\Model\AbstractModel $object) + { + $tableFieldsWithoutIdField = $this->getTableFieldsWithoutIdField(); + $select = $this->getConnection()->select(); + $select->from( + [$this->getMainTable()], + $tableFieldsWithoutIdField + ) + ->where('customer_group_id = ?', \Magento\Customer\Model\Group::CUST_GROUP_ALL); + + $query = $this->getConnection()->insertFromSelect( + $select, + $this->getMainTable(), + $tableFieldsWithoutIdField + ); + $this->getConnection()->query($query); + $lastInsertId = $this->getConnection()->lastInsertId(); + + $query = $this->getConnection()->deleteFromSelect( + $select, + $this->getMainTable() + ); + $this->getConnection()->query($query); + + $object->setId($lastInsertId); + } + + /** + * Get main table fields except of ID field. + * + * @return array + */ + private function getTableFieldsWithoutIdField() + { + $fields = $this->getConnection()->describeTable($this->getMainTable()); + if (isset($fields['customer_group_id'])) { + unset($fields['customer_group_id']); + } + + return array_keys($fields); + } } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Group/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Group/Collection.php index fa57ece536983..b93f3381b36d2 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Group/Collection.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Group/Collection.php @@ -1,6 +1,6 @@ request = $request; $this->urlBuilder = $urlBuilder; $this->scopeConfig = $scopeConfig; $this->customerSession = $customerSession; $this->urlEncoder = $urlEncoder; + $this->urlDecoder = $urlDecoder ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Url\DecoderInterface::class); + $this->hostChecker = $hostChecker ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Url\HostChecker::class); } /** @@ -95,7 +113,7 @@ public function getLoginUrl() public function getLoginUrlParams() { $params = []; - $referer = $this->request->getParam(self::REFERER_QUERY_PARAM_NAME); + $referer = $this->getRequestReferrer(); if (!$referer && !$this->scopeConfig->isSetFlag( self::XML_PATH_CUSTOMER_STARTUP_REDIRECT_TO_DASHBOARD, @@ -122,9 +140,10 @@ public function getLoginUrlParams() public function getLoginPostUrl() { $params = []; - if ($this->request->getParam(self::REFERER_QUERY_PARAM_NAME)) { + $referer = $this->getRequestReferrer(); + if ($referer) { $params = [ - self::REFERER_QUERY_PARAM_NAME => $this->request->getParam(self::REFERER_QUERY_PARAM_NAME), + self::REFERER_QUERY_PARAM_NAME => $referer, ]; } return $this->urlBuilder->getUrl('customer/account/loginPost', $params); @@ -220,4 +239,16 @@ public function getEmailConfirmationUrl($email = null) { return $this->urlBuilder->getUrl('customer/account/confirmation', ['email' => $email]); } + + /** + * @return mixed|null + */ + private function getRequestReferrer() + { + $referer = $this->request->getParam(self::REFERER_QUERY_PARAM_NAME); + if ($referer && $this->hostChecker->isOwnOrigin($this->urlDecoder->decode($referer))) { + return $referer; + } + return null; + } } diff --git a/app/code/Magento/Customer/Model/Vat.php b/app/code/Magento/Customer/Model/Vat.php index a1d22ccf6072f..32b312e994ce7 100644 --- a/app/code/Magento/Customer/Model/Vat.php +++ b/app/code/Magento/Customer/Model/Vat.php @@ -1,6 +1,6 @@ customerSetupFactory = $customerSetupFactory; $this->indexerRegistry = $indexerRegistry; $this->eavConfig = $eavConfig; + + $this->fieldDataConverterFactory = $fieldDataConverterFactory ?: ObjectManager::getInstance()->get( + FieldDataConverterFactory::class + ); } /** @@ -106,12 +134,149 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $this->upgradeCustomerPasswordResetlinkExpirationPeriodConfig($setup); } + if (version_compare($context->getVersion(), '2.0.9', '<')) { + $setup->getConnection()->beginTransaction(); + + try { + $this->migrateStoresAllowedCountriesToWebsite($setup); + $setup->getConnection()->commit(); + } catch (\Exception $e) { + $setup->getConnection()->rollBack(); + throw $e; + } + } + if (version_compare($context->getVersion(), '2.0.11', '<')) { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $fieldDataConverter->convert( + $setup->getConnection(), + $setup->getTable('customer_eav_attribute'), + 'attribute_id', + 'validate_rules' + ); + } + $indexer = $this->indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID); $indexer->reindexAll(); $this->eavConfig->clear(); $setup->endSetup(); } + /** + * Retrieve Store Manager + * + * @deprecated + * @return StoreManagerInterface + */ + private function getStoreManager() + { + if (!$this->storeManager) { + $this->storeManager = ObjectManager::getInstance()->get(StoreManagerInterface::class); + } + + return $this->storeManager; + } + + /** + * Retrieve Allowed Countries Reader + * + * @deprecated + * @return AllowedCountries + */ + private function getAllowedCountriesReader() + { + if (!$this->allowedCountriesReader) { + $this->allowedCountriesReader = ObjectManager::getInstance()->get(AllowedCountries::class); + } + + return $this->allowedCountriesReader; + } + + /** + * Merge allowed countries between different scopes + * + * @param array $countries + * @param array $newCountries + * @param string $identifier + * @return array + */ + private function mergeAllowedCountries(array $countries, array $newCountries, $identifier) + { + if (!isset($countries[$identifier])) { + $countries[$identifier] = $newCountries; + } else { + $countries[$identifier] = + array_replace($countries[$identifier], $newCountries); + } + + return $countries; + } + + /** + * Retrieve countries not depending on global scope + * + * @param string $scope + * @param int $scopeCode + * @return array + */ + private function getAllowedCountries($scope, $scopeCode) + { + $reader = $this->getAllowedCountriesReader(); + return $reader->makeCountriesUnique($reader->getCountriesFromConfig($scope, $scopeCode)); + } + + /** + * Merge allowed countries from stores to websites + * + * @param SetupInterface $setup + * @return void + */ + private function migrateStoresAllowedCountriesToWebsite(SetupInterface $setup) + { + $allowedCountries = []; + //Process Websites + foreach ($this->getStoreManager()->getStores() as $store) { + $allowedCountries = $this->mergeAllowedCountries( + $allowedCountries, + $this->getAllowedCountries(ScopeInterface::SCOPE_STORE, $store->getId()), + $store->getWebsiteId() + ); + } + //Process stores + foreach ($this->getStoreManager()->getWebsites() as $website) { + $allowedCountries = $this->mergeAllowedCountries( + $allowedCountries, + $this->getAllowedCountries(ScopeInterface::SCOPE_WEBSITE, $website->getId()), + $website->getId() + ); + } + + $connection = $setup->getConnection(); + + //Remove everything from stores scope + $connection->delete( + $setup->getTable('core_config_data'), + [ + 'path = ?' => AllowedCountries::ALLOWED_COUNTRIES_PATH, + 'scope = ?' => ScopeInterface::SCOPE_STORES + ] + ); + + //Update websites + foreach ($allowedCountries as $scopeId => $countries) { + $connection->update( + $setup->getTable('core_config_data'), + [ + 'value' => implode(',', $countries) + ], + [ + 'path = ?' => AllowedCountries::ALLOWED_COUNTRIES_PATH, + 'scope_id = ?' => $scopeId, + 'scope = ?' => ScopeInterface::SCOPE_WEBSITES + ] + ); + } + } + /** * @param array $entityAttributes * @param CustomerSetup $customerSetup diff --git a/app/code/Magento/Customer/Setup/UpgradeSchema.php b/app/code/Magento/Customer/Setup/UpgradeSchema.php old mode 100644 new mode 100755 index 18fc9b9f8d597..c4ab78f362fec --- a/app/code/Magento/Customer/Setup/UpgradeSchema.php +++ b/app/code/Magento/Customer/Setup/UpgradeSchema.php @@ -1,6 +1,6 @@ getVersion(), '2.0.10', '<')) { + $foreignKeys = $this->getForeignKeys($setup); + $this->dropForeignKeys($setup, $foreignKeys); + $this->alterTables($setup, $foreignKeys); + $this->createForeignKeys($setup, $foreignKeys); + } + $setup->endSetup(); } + + /** + * @param SchemaSetupInterface $setup + * @param array $keys + * @return void + */ + private function alterTables(SchemaSetupInterface $setup, array $keys) + { + $setup->getConnection()->modifyColumn( + $setup->getTable('customer_group'), + 'customer_group_id', + [ + 'type' => 'integer', + 'unsigned' => true, + 'identity' => true, + 'nullable' => false + ] + ); + foreach ($keys as $key) { + $description = $setup->getConnection()->describeTable($key['TABLE_NAME'])[$key['COLUMN_NAME']]; + $description['DATA_TYPE'] = 'int'; + $setup->getConnection()->modifyColumnByDdl( + $key['TABLE_NAME'], + $key['COLUMN_NAME'], + $description + ); + } + } + + /** + * @param SchemaSetupInterface $setup + * @param array $keys + * @return void + */ + private function dropForeignKeys(SchemaSetupInterface $setup, array $keys) + { + foreach ($keys as $key) { + $setup->getConnection()->dropForeignKey($key['TABLE_NAME'], $key['FK_NAME']); + } + } + + /** + * @param SchemaSetupInterface $setup + * @param array $keys + * @return void + */ + private function createForeignKeys(SchemaSetupInterface $setup, array $keys) + { + foreach ($keys as $key) { + $setup->getConnection()->addForeignKey( + $key['FK_NAME'], + $key['TABLE_NAME'], + $key['COLUMN_NAME'], + $key['REF_TABLE_NAME'], + $key['REF_COLUMN_NAME'], + $key['ON_DELETE'] + ); + } + } + + /** + * @param SchemaSetupInterface $setup + * @return array + */ + private function getForeignKeys(SchemaSetupInterface $setup) + { + $foreignKeys = []; + $keysTree = $setup->getConnection()->getForeignKeysTree(); + foreach ($keysTree as $indexes) { + foreach ($indexes as $index) { + if ( + $index['REF_TABLE_NAME'] == $setup->getTable('customer_group') + && $index['REF_COLUMN_NAME'] == 'customer_group_id' + ) { + $foreignKeys[] = $index; + } + + } + } + return $foreignKeys; + } } diff --git a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php index 05f56d2570273..67a3fb8f3a576 100644 --- a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php +++ b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php @@ -1,6 +1,6 @@ contextMock->expects($this->once()) ->method('getUrlBuilder') ->willReturn($this->urlBuilderMock); + $escaperMock = $this->getMockBuilder(\Magento\Framework\Escaper::class) + ->disableOriginalConstructor() + ->getMock(); + $escaperMock->method('escapeHtml') + ->willReturnCallback( + function ($string) { + return 'escapeHtml' . $string; + } + ); + $escaperMock->method('escapeUrl') + ->willReturnCallback( + function ($string) { + return 'escapeUrl' . $string; + } + ); + $this->contextMock->expects($this->once()) + ->method('getEscaper') + ->willReturn($escaperMock); $this->model = new AuthenticationPopup( $this->contextMock @@ -110,10 +128,10 @@ public function dataProviderGetConfig() 'reg', 'forgot', [ - 'autocomplete' => 'off', - 'customerRegisterUrl' => 'reg', - 'customerForgotPasswordUrl' => 'forgot', - 'baseUrl' => 'base', + 'autocomplete' => 'escapeHtmloff', + 'customerRegisterUrl' => 'escapeUrlreg', + 'customerForgotPasswordUrl' => 'escapeUrlforgot', + 'baseUrl' => 'escapeUrlbase', ], ], [ @@ -122,10 +140,10 @@ public function dataProviderGetConfig() 'reg', 'forgot', [ - 'autocomplete' => 'on', - 'customerRegisterUrl' => 'reg', - 'customerForgotPasswordUrl' => 'forgot', - 'baseUrl' => '', + 'autocomplete' => 'escapeHtmlon', + 'customerRegisterUrl' => 'escapeUrlreg', + 'customerForgotPasswordUrl' => 'escapeUrlforgot', + 'baseUrl' => 'escapeUrl', ], ], [ @@ -134,10 +152,10 @@ public function dataProviderGetConfig() '', 'forgot', [ - 'autocomplete' => 'off', - 'customerRegisterUrl' => '', - 'customerForgotPasswordUrl' => 'forgot', - 'baseUrl' => 'base', + 'autocomplete' => 'escapeHtmloff', + 'customerRegisterUrl' => 'escapeUrl', + 'customerForgotPasswordUrl' => 'escapeUrlforgot', + 'baseUrl' => 'escapeUrlbase', ], ], [ @@ -146,10 +164,10 @@ public function dataProviderGetConfig() 'reg', '', [ - 'autocomplete' => 'on', - 'customerRegisterUrl' => 'reg', - 'customerForgotPasswordUrl' => '', - 'baseUrl' => 'base', + 'autocomplete' => 'escapeHtmlon', + 'customerRegisterUrl' => 'escapeUrlreg', + 'customerForgotPasswordUrl' => 'escapeUrl', + 'baseUrl' => 'escapeUrlbase', ], ], ]; diff --git a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthorizationLinkTest.php b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthorizationLinkTest.php index ed639e51b5758..c5f71eb222088 100644 --- a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthorizationLinkTest.php +++ b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthorizationLinkTest.php @@ -1,6 +1,6 @@ disableOriginalConstructor() ->getMock(); - $scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $scopeConfigMock->expects($this->any()) - ->method('getValue') - ->willReturn('test@host.com'); - $this->authenticationMock = $this->getMockBuilder(AuthenticationInterface::class) ->disableOriginalConstructor() ->getMock(); @@ -157,11 +149,7 @@ protected function setUp() 'emailNotification', $this->emailNotification ); - $objectManager->setBackwardCompatibleProperty( - $this->model, - 'scopeConfig', - $scopeConfigMock - ); + $objectManager->setBackwardCompatibleProperty( $this->model, 'authentication', @@ -216,7 +204,6 @@ public function testGeneralSave() $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) ->getMockForAbstractClass(); - $currentCustomerMock = $this->getCurrentCustomerMock($customerId, $address); $newCustomerMock = $this->getNewCustomerMock($customerId, $address); @@ -412,7 +399,7 @@ public function changeEmailExceptionDataProvider() [ 'testNumber' => 2, 'exceptionClass' => \Magento\Framework\Exception\State\UserLockedException::class, - 'errorMessage' => __('The account is locked. Please wait and try again or contact %1.', 'test@host.com') + 'errorMessage' => __('You did not sign in correctly or your account is temporarily disabled.') ] ]; } diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/ForgotPasswordPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/ForgotPasswordPostTest.php index 18de7a0e88a02..3a942e5faeedf 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Account/ForgotPasswordPostTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Account/ForgotPasswordPostTest.php @@ -1,6 +1,6 @@ messageManager->expects($this->once()) ->method('addError') - ->with(__('Invalid login or password.')) + ->with(__('You did not sign in correctly or your account is temporarily disabled.')) ->willReturnSelf(); $this->session->expects($this->once()) @@ -581,10 +580,8 @@ protected function mockExceptions($exception, $username) break; case \Magento\Framework\Exception\State\UserLockedException::class: - $this->scopeConfig->expects($this->once())->method('getValue')->willReturn($email); $message = __( - 'The account is locked. Please wait and try again or contact %1.', - $email + 'You did not sign in correctly or your account is temporarily disabled.' ); $this->messageManager->expects($this->once()) ->method('addError') diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/LogoutTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/LogoutTest.php index 27d3895a2524d..ee60af62ade5d 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Account/LogoutTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Account/LogoutTest.php @@ -1,6 +1,6 @@ messageManager = $this->getMockBuilder( \Magento\Framework\Message\Manager::class )->disableOriginalConstructor()->setMethods( - ['addSuccess', 'addMessage', 'addException'] + ['addSuccess', 'addMessage', 'addException', 'addErrorMessage'] )->getMock(); $this->resultRedirectFactoryMock = $this->getMockBuilder( @@ -332,6 +332,56 @@ public function testResetPasswordActionCoreException() $this->_testedObject->execute(); } + public function testResetPasswordActionSecurityException() + { + $securityText = 'Security violation.'; + $exception = new \Magento\Framework\Exception\SecurityViolationException(__($securityText)); + $customerId = 1; + $email = 'some@example.com'; + $websiteId = 1; + + $this->_request->expects( + $this->once() + )->method( + 'getParam' + )->with( + $this->equalTo('customer_id'), + $this->equalTo(0) + )->will( + $this->returnValue($customerId) + ); + $customer = $this->getMockForAbstractClass( + \Magento\Customer\Api\Data\CustomerInterface::class, + ['getId', 'getEmail', 'getWebsiteId'] + ); + $customer->expects($this->once())->method('getEmail')->will($this->returnValue($email)); + $customer->expects($this->once())->method('getWebsiteId')->will($this->returnValue($websiteId)); + $this->_customerRepositoryMock->expects( + $this->once() + )->method( + 'getById' + )->with( + $customerId + )->will( + $this->returnValue($customer) + ); + $this->_customerAccountManagementMock->expects( + $this->once() + )->method( + 'initiatePasswordReset' + )->willThrowException($exception); + + $this->messageManager->expects( + $this->once() + )->method( + 'addErrorMessage' + )->with( + $this->equalTo($exception->getMessage()) + ); + + $this->_testedObject->execute(); + } + public function testResetPasswordActionCoreExceptionWarn() { $warningText = 'Warning'; diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php index 8fb48fe9f87e7..7fcb325ff35d4 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php @@ -1,6 +1,6 @@ $subscription, ]; - $filteredData = [ + $extractedData = [ 'entity_id' => $customerId, 'code' => 'value', 'coolness' => false, 'disable_auto_group_change' => 'false', ]; - $dataToCompact = [ + $compactedData = [ 'entity_id' => $customerId, 'code' => 'value', 'coolness' => false, 'disable_auto_group_change' => 'false', - CustomerInterface::DEFAULT_BILLING => false, - CustomerInterface::DEFAULT_SHIPPING => false, - 'confirmation' => false, - 'sendemail_store_id' => false, - 'extension_attributes' => false, + CustomerInterface::DEFAULT_BILLING => 2, + CustomerInterface::DEFAULT_SHIPPING => 2 ]; - $addressFilteredData = [ + $addressExtractedData = [ 'entity_id' => $addressId, - 'default_billing' => 'true', - 'default_shipping' => 'true', 'code' => 'value', 'coolness' => false, 'region' => 'region', 'region_id' => 'region_id', ]; - $addressDataToCompact = [ + $addressCompactedData = [ 'entity_id' => $addressId, 'default_billing' => 'true', 'default_shipping' => 'true', @@ -430,11 +425,11 @@ public function testExecuteWithExistentCustomer() $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') - ->willReturn($filteredData); + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('compactData') - ->with($dataToCompact) - ->willReturn($filteredData); + ->with($extractedData) + ->willReturn($compactedData); $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); @@ -445,11 +440,11 @@ public function testExecuteWithExistentCustomer() $customerAddressFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'address/' . $addressId) - ->willReturn($addressFilteredData); + ->willReturn($addressExtractedData); $customerAddressFormMock->expects($this->once()) ->method('compactData') - ->with($addressDataToCompact) - ->willReturn($addressFilteredData); + ->with($addressExtractedData) + ->willReturn($addressCompactedData); $customerAddressFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); @@ -625,8 +620,6 @@ public function testExecuteWithNewCustomer() '_template_' => '_template_', $addressId => [ 'entity_id' => $addressId, - 'default_billing' => 'false', - 'default_shipping' => 'false', 'code' => 'value', 'coolness' => false, 'region' => 'region', @@ -635,32 +628,12 @@ public function testExecuteWithNewCustomer() ], 'subscription' => $subscription, ]; - $filteredData = [ + $extractedData = [ 'coolness' => false, 'disable_auto_group_change' => 'false', ]; - $dataToCompact = [ - 'coolness' => false, - 'disable_auto_group_change' => 'false', - CustomerInterface::DEFAULT_BILLING => false, - CustomerInterface::DEFAULT_SHIPPING => false, - 'confirmation' => false, - 'sendemail_store_id' => false, - 'extension_attributes' => false, - ]; - $addressFilteredData = [ + $addressExtractedData = [ 'entity_id' => $addressId, - 'default_billing' => 'false', - 'default_shipping' => 'false', - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ]; - $addressDataToCompact = [ - 'entity_id' => $addressId, - 'default_billing' => 'false', - 'default_shipping' => 'false', 'code' => 'value', 'coolness' => false, 'region' => 'region', @@ -739,11 +712,11 @@ public function testExecuteWithNewCustomer() $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') - ->willReturn($filteredData); + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('compactData') - ->with($dataToCompact) - ->willReturn($filteredData); + ->with($extractedData) + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); @@ -754,11 +727,11 @@ public function testExecuteWithNewCustomer() $customerAddressFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'address/' . $addressId) - ->willReturn($addressFilteredData); + ->willReturn($addressExtractedData); $customerAddressFormMock->expects($this->once()) ->method('compactData') - ->with($addressDataToCompact) - ->willReturn($addressFilteredData); + ->with($addressExtractedData) + ->willReturn($addressExtractedData); $customerAddressFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); @@ -910,19 +883,10 @@ public function testExecuteWithNewCustomerAndValidationException() ], 'subscription' => $subscription, ]; - $filteredData = [ + $extractedData = [ 'coolness' => false, 'disable_auto_group_change' => 'false', ]; - $dataToCompact = [ - 'coolness' => false, - 'disable_auto_group_change' => 'false', - CustomerInterface::DEFAULT_BILLING => false, - CustomerInterface::DEFAULT_SHIPPING => false, - 'confirmation' => false, - 'sendemail_store_id' => false, - 'extension_attributes' => false, - ]; /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */ $attributeMock = $this->getMockBuilder( @@ -971,11 +935,11 @@ public function testExecuteWithNewCustomerAndValidationException() $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') - ->willReturn($filteredData); + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('compactData') - ->with($dataToCompact) - ->willReturn($filteredData); + ->with($extractedData) + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); @@ -1062,19 +1026,10 @@ public function testExecuteWithNewCustomerAndLocalizedException() ], 'subscription' => $subscription, ]; - $filteredData = [ + $extractedData = [ 'coolness' => false, 'disable_auto_group_change' => 'false', ]; - $dataToCompact = [ - 'coolness' => false, - 'disable_auto_group_change' => 'false', - CustomerInterface::DEFAULT_BILLING => false, - CustomerInterface::DEFAULT_SHIPPING => false, - 'confirmation' => false, - 'sendemail_store_id' => false, - 'extension_attributes' => false, - ]; /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */ $attributeMock = $this->getMockBuilder( @@ -1124,11 +1079,11 @@ public function testExecuteWithNewCustomerAndLocalizedException() $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') - ->willReturn($filteredData); + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('compactData') - ->with($dataToCompact) - ->willReturn($filteredData); + ->with($extractedData) + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); @@ -1214,18 +1169,9 @@ public function testExecuteWithNewCustomerAndException() ], 'subscription' => $subscription, ]; - $filteredData = [ - 'coolness' => false, - 'disable_auto_group_change' => 'false', - ]; - $dataToCompact = [ + $extractedData = [ 'coolness' => false, 'disable_auto_group_change' => 'false', - CustomerInterface::DEFAULT_BILLING => false, - CustomerInterface::DEFAULT_SHIPPING => false, - 'confirmation' => false, - 'sendemail_store_id' => false, - 'extension_attributes' => false, ]; /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */ @@ -1275,11 +1221,11 @@ public function testExecuteWithNewCustomerAndException() $customerFormMock->expects($this->once()) ->method('extractData') ->with($this->requestMock, 'customer') - ->willReturn($filteredData); + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('compactData') - ->with($dataToCompact) - ->willReturn($filteredData); + ->with($extractedData) + ->willReturn($extractedData); $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php index 34b44671ce02b..ace442a7ed03a 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php b/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php index 4329c33f3161f..13bd067dbff01 100644 --- a/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php +++ b/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php @@ -1,6 +1,6 @@ request = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class); @@ -134,6 +140,10 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); + $this->hostChecker = $this->getMockBuilder(HostChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); $this->model = $objectManager->getObject( \Magento\Customer\Model\Account\Redirect::class, @@ -145,7 +155,8 @@ protected function setUp() 'url' => $this->url, 'urlDecoder' => $this->urlDecoder, 'customerUrl' => $this->customerUrl, - 'resultFactory' => $this->resultFactory + 'resultFactory' => $this->resultFactory, + 'hostChecker' => $this->hostChecker ] ); } @@ -254,6 +265,7 @@ public function testGetRedirect( $this->resultRedirect->expects($this->once()) ->method('setUrl') + ->with($beforeAuthUrl) ->willReturnSelf(); $this->resultFactory->expects($this->once()) @@ -286,6 +298,7 @@ public function getRedirectDataProvider() return [ // Loggend In, Redirect by Referer [1, 2, 'referer', 'base', '', '', 'account', '', '', '', true, false], + [1, 2, 'http://referer.com/', 'http://base.com/', '', '', 'account', '', '', 'dashboard', true, false], // Loggend In, Redirect by AfterAuthUrl [1, 2, 'referer', 'base', '', 'defined', 'account', '', '', '', true, true], // Not logged In, Redirect by LoginUrl diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php index 9eed3d2b044ca..ebb64e7e6526c 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php @@ -1,6 +1,6 @@ emailNotificationMock->expects($this->once()) @@ -1168,7 +1168,7 @@ public function testInitiatePasswordResetEmailReset() $templateIdentifier = 'Template Identifier'; $sender = 'Sender'; - mt_srand(mt_rand() + (100000000 * microtime()) % PHP_INT_MAX); + mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); $this->emailNotificationMock->expects($this->once()) @@ -1194,7 +1194,7 @@ public function testInitiatePasswordResetNoTemplate() $templateIdentifier = 'Template Identifier'; $sender = 'Sender'; - mt_srand(mt_rand() + (100000000 * microtime()) % PHP_INT_MAX); + mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash); diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php index 4e0922721de5c..5b2d0afe7c720 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php @@ -1,6 +1,6 @@ markTestSkipped('Need to revert changes from MAGETWO-39106 and then modify this test.'); $expected = [ 'key' => 'value', - 'array' => 'value1', + 'street' => 'value1', ]; $key = [ 'key' => 'value', - 'array' => [ + 'street' => [ 'key1' => 'value1', ] ]; @@ -337,31 +336,31 @@ public function validateDataProvider() return [ 'firstname' => [ array_merge(array_diff_key($data, ['firstname' => '']), ['country_id' => $countryId++]), - ['Please enter the first name.'], + ['firstname is a required field.'], ], 'lastname' => [ array_merge(array_diff_key($data, ['lastname' => '']), ['country_id' => $countryId++]), - ['Please enter the last name.'], + ['lastname is a required field.'], ], 'street' => [ array_merge(array_diff_key($data, ['street' => '']), ['country_id' => $countryId++]), - ['Please enter the street.'], + ['street is a required field.'], ], 'city' => [ array_merge(array_diff_key($data, ['city' => '']), ['country_id' => $countryId++]), - ['Please enter the city.'], + ['city is a required field.'], ], 'telephone' => [ array_merge(array_diff_key($data, ['telephone' => '']), ['country_id' => $countryId++]), - ['Please enter the phone number.'], + ['telephone is a required field.'], ], 'postcode' => [ array_merge(array_diff_key($data, ['postcode' => '']), ['country_id' => $countryId++]), - ['Please enter the zip/postal code.'], + ['postcode is a required field.'], ], 'country_id' => [ array_diff_key($data, ['country_id' => '']), - ['Please enter the country.'], + ['countryId is a required field.'], ], 'validated' => [array_merge($data, ['country_id' => $countryId++]), true], ]; diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/Config/ConverterTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/Config/ConverterTest.php index 866a3cc622a7a..2ab773e698ad1 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/Config/ConverterTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/Config/ConverterTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_one.xml b/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_one.xml index cbb32e5347cd2..fe42eff100fde 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_one.xml +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_one.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_two.xml b/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_two.xml index c5a18ed44d499..0b46b5291ec14 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_two.xml +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/Config/_files/formats_two.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/ConfigTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/ConfigTest.php index 5c2aeec636cec..9bb5f39d2188f 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/ConfigTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/ConfigTest.php @@ -1,6 +1,6 @@ _storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); - $this->_scopeConfigMock = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); + $cacheId = 'cache_id'; + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $this->scopeConfigMock = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); - $this->_readerMock = $this->getMock( + $readerMock = $this->getMock( \Magento\Customer\Model\Address\Config\Reader::class, [], [], '', false ); - $this->_cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); - $this->_storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); - $this->_storeManagerMock->expects( + $cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); + $storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); + $storeManagerMock->expects( $this->once() )->method( 'getStore' )->will( - $this->returnValue($this->_storeMock) + $this->returnValue($this->storeMock) ); - $this->_addressHelperMock = $this->getMock(\Magento\Customer\Helper\Address::class, [], [], '', false); + $this->addressHelperMock = $this->getMock(\Magento\Customer\Helper\Address::class, [], [], '', false); - $this->_cacheMock->expects( + $cacheMock->expects( $this->once() )->method( 'load' )->with( - $this->_cacheId + $cacheId )->will( $this->returnValue(false) ); $fixtureConfigData = require __DIR__ . '/Config/_files/formats_merged.php'; - $this->_readerMock->expects($this->once())->method('read')->will($this->returnValue($fixtureConfigData)); - - $this->_cacheMock->expects( - $this->once() - )->method( - 'save' - )->with( - serialize($fixtureConfigData), - $this->_cacheId - ); - - $this->_model = new \Magento\Customer\Model\Address\Config( - $this->_readerMock, - $this->_cacheMock, - $this->_storeManagerMock, - $this->_addressHelperMock, - $this->_scopeConfigMock, - $this->_cacheId + $readerMock->expects($this->once())->method('read')->will($this->returnValue($fixtureConfigData)); + + $cacheMock->expects($this->once()) + ->method('save') + ->with( + json_encode($fixtureConfigData), + $cacheId + ); + + $serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); + $serializerMock->method('serialize') + ->willReturn(json_encode($fixtureConfigData)); + $serializerMock->method('unserialize') + ->willReturn($fixtureConfigData); + + $this->model = $objectManagerHelper->getObject( + \Magento\Customer\Model\Address\Config::class, + [ + 'reader' => $readerMock, + 'cache' => $cacheMock, + 'storeManager' => $storeManagerMock, + 'scopeConfig' => $this->scopeConfigMock, + 'cacheId' => $cacheId, + 'serializer' => $serializerMock, + 'addressHelper' => $this->addressHelperMock, + ] ); } public function testGetStore() { - $this->assertEquals($this->_storeMock, $this->_model->getStore()); + $this->assertEquals($this->storeMock, $this->model->getStore()); } public function testSetStore() { - $this->_model->setStore($this->_storeMock); - - //no call to $_storeManagerMock's method - $this->assertEquals($this->_storeMock, $this->_model->getStore()); + $this->model->setStore($this->storeMock); + $this->assertEquals($this->storeMock, $this->model->getStore()); } public function testGetFormats() { - $this->_storeMock->expects($this->once())->method('getId'); + $this->storeMock->expects($this->once())->method('getId'); - $this->_scopeConfigMock->expects($this->any())->method('getValue')->will($this->returnValue('someValue')); + $this->scopeConfigMock->expects($this->any())->method('getValue')->will($this->returnValue('someValue')); $rendererMock = $this->getMock(\Magento\Framework\DataObject::class); - $this->_addressHelperMock->expects( + $this->addressHelperMock->expects( $this->any() )->method( 'getRenderer' @@ -160,6 +148,6 @@ public function testGetFormats() ); $expectedResult = [$firstExpected, $secondExpected]; - $this->assertEquals($expectedResult, $this->_model->getFormats()); + $this->assertEquals($expectedResult, $this->model->getFormats()); } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/MapperTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/MapperTest.php index cea1bc43001fc..2493272fb90f0 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/MapperTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/MapperTest.php @@ -1,6 +1,6 @@ groupServiceMock = $this->getMock(\Magento\Customer\Api\GroupManagementInterface::class); $this->converterMock = $this->getMock(\Magento\Framework\Convert\DataObject::class, [], [], '', false); - $this->model = - new \Magento\Customer\Model\Config\Source\Group\Multiselect($this->groupServiceMock, $this->converterMock); + $this->groupSourceLoggedInOnly = $this->getMockBuilder(GroupSourceLoggedInOnlyInterface::class)->getMock(); + $this->model = new \Magento\Customer\Model\Config\Source\Group\Multiselect( + $this->groupServiceMock, + $this->converterMock, + $this->groupSourceLoggedInOnly + ); } public function testToOptionArray() { $expectedValue = ['General', 'Retail']; - $this->groupServiceMock->expects($this->once()) - ->method('getLoggedInGroups') - ->will($this->returnValue($expectedValue)); - $this->converterMock->expects($this->once())->method('toOptionArray') - ->with($expectedValue, 'id', 'code')->will($this->returnValue($expectedValue)); + $this->groupServiceMock->expects($this->never())->method('getLoggedInGroups'); + $this->converterMock->expects($this->never())->method('toOptionArray'); + $this->groupSourceLoggedInOnly->expects($this->once())->method('toOptionArray')->willReturn($expectedValue); $this->assertEquals($expectedValue, $this->model->toOptionArray()); } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Config/Source/GroupTest.php b/app/code/Magento/Customer/Test/Unit/Model/Config/Source/GroupTest.php index edb3405451eca..7602e13e80b3c 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Config/Source/GroupTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Config/Source/GroupTest.php @@ -1,15 +1,26 @@ groupServiceMock = $this->getMock(\Magento\Customer\Api\GroupManagementInterface::class); - $this->converterMock = $this->getMock(\Magento\Framework\Convert\DataObject::class, [], [], '', false); - $this->model = - new \Magento\Customer\Model\Config\Source\Group($this->groupServiceMock, $this->converterMock); + $this->groupServiceMock = $this->getMock(GroupManagementInterface::class); + $this->converterMock = $this->getMock(DataObject::class, [], [], '', false); + $this->groupSource = $this->getMockBuilder(GroupSourceLoggedInOnlyInterface::class) + ->getMockForAbstractClass(); + $this->model = (new ObjectManager($this))->getObject( + Group::class, + [ + 'groupManagement' => $this->groupServiceMock, + 'converter' => $this->converterMock, + 'groupSourceForLoggedInCustomers' => $this->groupSource, + ] + ); } public function testToOptionArray() { $expectedValue = ['General', 'Retail']; - $this->groupServiceMock->expects($this->once()) - ->method('getLoggedInGroups') - ->will($this->returnValue($expectedValue)); - $this->converterMock->expects($this->once())->method('toOptionArray') - ->with($expectedValue, 'id', 'code')->will($this->returnValue($expectedValue)); + $this->groupServiceMock->expects($this->never())->method('getLoggedInGroups'); + $this->converterMock->expects($this->never())->method('toOptionArray'); + + $this->groupSource->expects($this->once()) + ->method('toOptionArray') + ->willReturn($expectedValue); + array_unshift($expectedValue, ['value' => '', 'label' => __('-- Please Select --')]); $this->assertEquals($expectedValue, $this->model->toOptionArray()); } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php index 4d7a9b96919cf..6d4d08e12e9a2 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/Attribute/Backend/BillingTest.php @@ -1,6 +1,6 @@ getObject( \Magento\Customer\Model\Customer\DataProvider::class, [ @@ -227,6 +230,29 @@ public function getAttributesMetaDataProvider() ], ], ], + 'country_id' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'filterBy' => [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ] + ], + ], + ], + ] ], ], ] @@ -298,7 +324,7 @@ protected function getTypeAddressMock() $typeAddressMock->expects($this->once()) ->method('getAttributeCollection') - ->willReturn($this->getAttributeMock()); + ->willReturn($this->getAttributeMock('address')); return $typeAddressMock; } @@ -306,7 +332,7 @@ protected function getTypeAddressMock() /** * @return AbstractAttribute[]|\PHPUnit_Framework_MockObject_MockObject[] */ - protected function getAttributeMock() + protected function getAttributeMock($type = 'customer') { $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) ->setMethods(['getAttributeCode', 'getDataUsingMethod', 'usesSource', 'getSource']) @@ -365,10 +391,66 @@ function ($origName) { [$attributeMock, $this->logicalNot($this->isEmpty()), []], [$attributeBooleanMock, $this->logicalNot($this->isEmpty()), []], ]); + $mocks = [$attributeMock, $attributeBooleanMock]; + + if ($type == "address") { + $mocks[] = $this->getCountryAttrMock(); + } + return $mocks; + } + + private function getCountryAttrMock() + { + $countryByWebsiteMock = $this->getMockBuilder(CountryWithWebsites::class) + ->disableOriginalConstructor() + ->getMock(); + $countryByWebsiteMock->expects($this->any()) + ->method('getAllOptions') + ->willReturn('test-options'); + $shareMock = $this->getMockBuilder(Share::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); + $objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap([ + [CountryWithWebsites::class, $countryByWebsiteMock], + [Share::class, $shareMock], + ]); + \Magento\Framework\App\ObjectManager::setInstance($objectManagerMock); + $countryAttrMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods(['getAttributeCode', 'getDataUsingMethod', 'usesSource', 'getSource']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); - return [$attributeMock, $attributeBooleanMock]; + $countryAttrMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn('country_id'); + + $countryAttrMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback( + function ($origName) { + return $origName; + } + ); + $countryAttrMock->expects($this->any()) + ->method('getLabel') + ->willReturn(__('frontend_label')); + $countryAttrMock->expects($this->any()) + ->method('usesSource') + ->willReturn(true); + $countryAttrMock->expects($this->any()) + ->method('getSource') + ->willReturn(null); + + return $countryAttrMock; } + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function testGetData() { $customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) @@ -478,6 +560,10 @@ public function testGetData() ); } + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function testGetDataWithCustomerFormData() { $customerId = 11; @@ -591,6 +677,10 @@ public function testGetDataWithCustomerFormData() $this->assertEquals([$customerId => $customerFormData], $dataProvider->getData()); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @return void + */ public function testGetDataWithCustomAttributeImage() { $customerId = 1; @@ -598,6 +688,7 @@ public function testGetDataWithCustomAttributeImage() $filename = '/filename.ext1'; $viewUrl = 'viewUrl'; + $mime = 'image/png'; $expectedData = [ $customerId => [ @@ -609,6 +700,7 @@ public function testGetDataWithCustomAttributeImage() 'size' => 1, 'url' => $viewUrl, 'name' => 'filename.ext1', + 'type' => $mime, ], ], ], @@ -688,6 +780,10 @@ public function testGetDataWithCustomAttributeImage() ->method('getViewUrl') ->with('/filename.ext1', 'image') ->willReturn($viewUrl); + $this->fileProcessor->expects($this->once()) + ->method('getMimeType') + ->with($filename) + ->willReturn($mime); $objectManager = new ObjectManager($this); $dataProvider = $objectManager->getObject( @@ -812,6 +908,10 @@ public function testGetDataWithCustomAttributeImageNoData() $this->assertEquals($expectedData, $dataProvider->getData()); } + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function testGetAttributesMetaWithCustomAttributeImage() { $maxFileSize = 1000; diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/NotificationStorageTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/NotificationStorageTest.php index 0d2b32f747a80..932361bd89679 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/NotificationStorageTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/NotificationStorageTest.php @@ -1,87 +1,93 @@ cache = $this->getMockBuilder(\Magento\Framework\Cache\FrontendInterface::class) - ->getMockForAbstractClass(); - $this->model = new NotificationStorage($this->cache); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->cacheMock = $this->getMock(\Magento\Framework\Cache\FrontendInterface::class); + $this->notificationStorage = $objectManager->getObject( + NotificationStorage::class, + ['cache' => $this->cacheMock] + ); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); + $objectManager->setBackwardCompatibleProperty($this->notificationStorage, 'serializer', $this->serializerMock); } public function testAdd() { $customerId = 1; $notificationType = 'some_type'; - $this->cache->expects($this->once()) + $data = [ + 'customer_id' => $customerId, + 'notification_type' => $notificationType + ]; + $serializedData = 'serialized data'; + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($data) + ->willReturn($serializedData); + $this->cacheMock->expects($this->once()) ->method('save') ->with( - serialize([ - 'customer_id' => $customerId, - 'notification_type' => $notificationType - ]), + $serializedData, $this->getCacheKey($notificationType, $customerId) ); - $this->model->add($notificationType, $customerId); + $this->notificationStorage->add($notificationType, $customerId); } public function testIsExists() { $customerId = 1; $notificationType = 'some_type'; - $this->cache->expects($this->once()) + $this->cacheMock->expects($this->once()) ->method('test') ->with($this->getCacheKey($notificationType, $customerId)) ->willReturn(true); - $this->assertTrue($this->model->isExists($notificationType, $customerId)); + $this->assertTrue($this->notificationStorage->isExists($notificationType, $customerId)); } public function testRemove() { $customerId = 1; $notificationType = 'some_type'; - $this->cache->expects($this->once()) + $this->cacheMock->expects($this->once()) ->method('remove') ->with($this->getCacheKey($notificationType, $customerId)); - $this->model->remove($notificationType, $customerId); + $this->notificationStorage->remove($notificationType, $customerId); } /** - * Retrieve cache key + * Get cache key * * @param string $notificationType * @param string $customerId * @return string */ - protected function getCacheKey($notificationType, $customerId) + private function getCacheKey($notificationType, $customerId) { return 'notification_' . $notificationType . '_' . $customerId; } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/Source/GroupTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/Source/GroupTest.php index d9ca3bdc1ba8e..7a1eadb4b371c 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/Source/GroupTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/Source/GroupTest.php @@ -1,6 +1,6 @@ mediaDirectory = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\WriteInterface::class) @@ -60,6 +65,10 @@ protected function setUp() $this->urlEncoder = $this->getMockBuilder(\Magento\Framework\Url\EncoderInterface::class) ->getMockForAbstractClass(); + + $this->mime = $this->getMockBuilder(\Magento\Framework\File\Mime::class) + ->disableOriginalConstructor() + ->getMock(); } private function getModel($entityTypeCode, array $allowedExtensions = []) @@ -70,6 +79,7 @@ private function getModel($entityTypeCode, array $allowedExtensions = []) $this->urlBuilder, $this->urlEncoder, $entityTypeCode, + $this->mime, $allowedExtensions ); return $model; @@ -376,4 +386,26 @@ public function testMoveTemporaryFileWithException() $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); $model->moveTemporaryFile($filePath); } + + public function testGetMimeType() + { + $fileName = '/filename.ext1'; + $absoluteFilePath = '/absolute_path/customer/filename.ext1'; + + $expected = 'ext1'; + + $this->mediaDirectory->expects($this->once()) + ->method('getAbsolutePath') + ->with(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . ltrim($fileName, '/')) + ->willReturn($absoluteFilePath); + + $this->mime->expects($this->once()) + ->method('getMimeType') + ->with($absoluteFilePath) + ->willReturn($expected); + + $model = $this->getModel(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); + + $this->assertEquals($expected, $model->getMimeType($fileName)); + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/FileUploaderTest.php b/app/code/Magento/Customer/Test/Unit/Model/FileUploaderTest.php index 8a415a8883334..3285903e8c693 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/FileUploaderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/FileUploaderTest.php @@ -1,6 +1,6 @@ shareConfig = $this->getMockBuilder(Share::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManager = $this->getMock(StoreManagerInterface::class); + + $this->plugin = new AllowedCountries($this->shareConfig, $this->storeManager); + } + + public function testGetAllowedCountriesWithGlobalScope() + { + $expectedFilter = 1; + $expectedScope = ScopeInterface::SCOPE_WEBSITES; + + $this->shareConfig->expects($this->once()) + ->method('isGlobalScope') + ->willReturn(true); + $originalAllowedCountriesMock = $this->getMockBuilder(\Magento\Directory\Model\AllowedCountries::class) + ->disableOriginalConstructor() + ->getMock(); + $websiteMock = $this->getMock(WebsiteInterface::class); + $websiteMock->expects($this->once()) + ->method('getId') + ->willReturn($expectedFilter); + $this->storeManager->expects($this->once()) + ->method('getWebsites') + ->willReturn([$websiteMock]); + + $this->assertEquals( + [$expectedScope, [$expectedFilter]], + $this->plugin->beforeGetAllowedCountries($originalAllowedCountriesMock) + ); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php b/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php index b8da1b863aad4..f5d106af276e7 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php @@ -1,6 +1,6 @@ countriesFactoryMock = + $this->getMockBuilder(\Magento\Directory\Model\ResourceModel\Country\CollectionFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->allowedCountriesMock = $this->getMockBuilder(AllowedCountries::class) + ->disableOriginalConstructor() + ->getMock(); + $eavCollectionFactoryMock = + $this->getMockBuilder(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\CollectionFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $optionsFactoryMock = + $this->getMockBuilder(\Magento\Eav\Model\ResourceModel\Entity\Attribute\OptionFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManagerMock = $this->getMock(StoreManagerInterface::class); + $this->shareConfigMock = $this->getMockBuilder(Share::class) + ->disableOriginalConstructor() + ->getMock(); + $this->countryByWebsite = new CountryWithWebsites( + $eavCollectionFactoryMock, + $optionsFactoryMock, + $this->countriesFactoryMock, + $this->allowedCountriesMock, + $this->storeManagerMock, + $this->shareConfigMock + ); + } + + public function testGetAllOptions() + { + $website1 = $this->getMock(WebsiteInterface::class); + $website2 = $this->getMock(WebsiteInterface::class); + + $website1->expects($this->atLeastOnce()) + ->method('getId') + ->willReturn(1); + $website2->expects($this->atLeastOnce()) + ->method('getId') + ->willReturn(2); + $this->storeManagerMock->expects($this->once()) + ->method('getWebsites') + ->willReturn([$website1, $website2]); + $collectionMock = $this->getMockBuilder(AbstractDb::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->allowedCountriesMock->expects($this->exactly(2)) + ->method('getAllowedCountries') + ->withConsecutive( + ['website', 1], + ['website', 2] + ) + ->willReturnMap([ + ['website', 1, ['AM' => 'AM']], + ['website', 2, ['AM' => 'AM', 'DZ' => 'DZ']] + ]); + $this->countriesFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($collectionMock); + $collectionMock->expects($this->once()) + ->method('addFieldToFilter') + ->with('country_id', ['in' => ['AM' => 'AM', 'DZ' => 'DZ']]) + ->willReturnSelf(); + $collectionMock->expects($this->once()) + ->method('toOptionArray') + ->willReturn([ + ['value' => 'AM', 'label' => 'UZ'] + ]); + + $this->assertEquals([ + ['value' => 'AM', 'label' => 'UZ', 'website_ids' => [1, 2]] + ], $this->countryByWebsite->getAllOptions()); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/DeleteRelationTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/DeleteRelationTest.php index 15e3958dd4974..2c391f5d611e1 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/DeleteRelationTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/DeleteRelationTest.php @@ -1,6 +1,6 @@ address->expects($this->once()) ->method('setCustomer') ->with($this->customer); + $this->address->expects($this->once()) + ->method('validate') + ->willReturn(true); $this->address->expects($this->once()) ->method('save'); $this->addressRegistry->expects($this->once()) @@ -208,9 +212,6 @@ public function testSave() $this->address->expects($this->once()) ->method('getDataModel') ->willReturn($customerAddress); - $this->address->expects($this->once()) - ->method('getShouldIgnoreValidation') - ->willReturn(true); $this->repository->save($customerAddress); } @@ -222,6 +223,7 @@ public function testSaveWithException() { $customerId = 34; $addressId = 53; + $errors[] = __('Please enter the state/province.'); $customerAddress = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\AddressInterface::class, [], @@ -245,7 +247,9 @@ public function testSaveWithException() $this->address->expects($this->once()) ->method('updateData') ->with($customerAddress); - $this->prepareMocksForInvalidAddressValidation(); + $this->address->expects($this->once()) + ->method('validate') + ->willReturn($errors); $this->repository->save($customerAddress); } @@ -258,6 +262,7 @@ public function testSaveWithInvalidRegion() { $customerId = 34; $addressId = 53; + $errors[] = __('region is a required field.'); $customerAddress = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\AddressInterface::class, [], @@ -281,60 +286,13 @@ public function testSaveWithInvalidRegion() $this->address->expects($this->once()) ->method('updateData') ->with($customerAddress); - $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false); - $regionCollection = $this->getMock( - \Magento\Directory\Model\ResourceModel\Region\Collection::class, - [], - [], - '', - false - ); - $this->address->expects($this->once()) - ->method('getShouldIgnoreValidation') - ->willReturn(false); - $this->address->expects($this->atLeastOnce()) - ->method('getCountryId') - ->willReturn(1); - $this->address->expects($this->once()) - ->method('getFirstname') - ->willReturn('firstname'); - $this->address->expects($this->once()) - ->method('getLastname') - ->willReturn('lastname'); - $this->address->expects($this->once()) - ->method('getStreetLine') - ->with(1) - ->willReturn('street line'); - $this->address->expects($this->once()) - ->method('getCity') - ->willReturn('city'); - $this->address->expects($this->once()) - ->method('getTelephone') - ->willReturn('23423423423'); $this->address->expects($this->never()) ->method('getRegionId') ->willReturn(null); - - $this->directoryData->expects($this->once()) - ->method('getCountriesWithOptionalZip') - ->willReturn([1]); - $this->address->expects($this->once()) - ->method('getCountryModel') - ->willReturn($countryModel); - $countryModel->expects($this->once()) - ->method('getRegionCollection') - ->willReturn($regionCollection); - $regionCollection->expects($this->once()) - ->method('count') - ->willReturn(0); - $this->directoryData->expects($this->once()) - ->method('isRegionRequired') - ->with(1) - ->willReturn(true); $this->address->expects($this->once()) - ->method('getRegion') - ->willReturn(''); + ->method('validate') + ->willReturn($errors); $this->repository->save($customerAddress); } @@ -347,6 +305,7 @@ public function testSaveWithInvalidRegionId() { $customerId = 34; $addressId = 53; + $errors[] = __('regionId is a required field.'); $customerAddress = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\AddressInterface::class, [], @@ -370,114 +329,14 @@ public function testSaveWithInvalidRegionId() $this->address->expects($this->once()) ->method('updateData') ->with($customerAddress); - $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false); - $regionCollection = $this->getMock( - \Magento\Directory\Model\ResourceModel\Region\Collection::class, - [], - [], - '', - false - ); - - $this->address->expects($this->once()) - ->method('getShouldIgnoreValidation') - ->willReturn(false); - $this->address->expects($this->atLeastOnce()) - ->method('getCountryId') - ->willReturn(1); - $this->address->expects($this->once()) - ->method('getFirstname') - ->willReturn('firstname'); - $this->address->expects($this->once()) - ->method('getLastname') - ->willReturn('lastname'); - $this->address->expects($this->once()) - ->method('getStreetLine') - ->with(1) - ->willReturn('street line'); - $this->address->expects($this->once()) - ->method('getCity') - ->willReturn('city'); - $this->address->expects($this->once()) - ->method('getTelephone') - ->willReturn('23423423423'); - $this->address->expects($this->once()) - ->method('getRegionId') - ->willReturn(2); - - $this->directoryData->expects($this->once()) - ->method('getCountriesWithOptionalZip') - ->willReturn([1]); - $this->address->expects($this->once()) - ->method('getCountryModel') - ->willReturn($countryModel); - $countryModel->expects($this->once()) - ->method('getRegionCollection') - ->willReturn($regionCollection); - $regionCollection->expects($this->atLeastOnce()) - ->method('count') - ->willReturn(2); - $regionCollection->expects($this->once()) - ->method('getData') - ->willReturn([5, 6, 7, 8, 9]); - $this->directoryData->expects($this->once()) - ->method('isRegionRequired') - ->with(1) - ->willReturn(true); $this->address->expects($this->never()) ->method('getRegion') ->willReturn(''); - - $this->repository->save($customerAddress); - } - - protected function prepareMocksForInvalidAddressValidation() - { - $countryModel = $this->getMock(\Magento\Directory\Model\Country::class, [], [], '', false); - $regionCollection = $this->getMock( - \Magento\Directory\Model\ResourceModel\Region\Collection::class, - [], - [], - '', - false - ); - - $this->address->expects($this->once()) - ->method('getShouldIgnoreValidation') - ->willReturn(false); - $this->address->expects($this->atLeastOnce()) - ->method('getCountryId'); - $this->address->expects($this->once()) - ->method('getFirstname'); - $this->address->expects($this->once()) - ->method('getLastname'); - $this->address->expects($this->once()) - ->method('getStreetLine') - ->with(1); $this->address->expects($this->once()) - ->method('getCity'); - $this->address->expects($this->once()) - ->method('getTelephone'); - $this->address->expects($this->never()) - ->method('getRegionId') - ->willReturn(null); + ->method('validate') + ->willReturn($errors); - $this->directoryData->expects($this->once()) - ->method('getCountriesWithOptionalZip') - ->willReturn([]); - $this->address->expects($this->once()) - ->method('getCountryModel') - ->willReturn($countryModel); - $countryModel->expects($this->once()) - ->method('getRegionCollection') - ->willReturn($regionCollection); - $regionCollection->expects($this->once()) - ->method('count') - ->willReturn(0); - $this->directoryData->expects($this->once()) - ->method('isRegionRequired') - ->with(null) - ->willReturn(true); + $this->repository->save($customerAddress); } public function testGetById() diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressTest.php index 27358af372250..b25f63bcfc663 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/AddressTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Customer\Model\ResourceModel\Customer::class, [], [], '', false); $this->customerRegistry = $this->getMock(\Magento\Customer\Model\CustomerRegistry::class, [], [], '', false); $this->dataObjectHelper = $this->getMock(\Magento\Framework\Api\DataObjectHelper::class, [], [], '', false); - $this->customerFactory = $this->getMock( - \Magento\Customer\Model\CustomerFactory::class, - ['create'], - [], - '', - false - ); + $this->customerFactory = + $this->getMock(\Magento\Customer\Model\CustomerFactory::class, ['create'], [], '', false); $this->customerSecureFactory = $this->getMock( \Magento\Customer\Model\Data\CustomerSecureFactory::class, ['create'], @@ -115,7 +110,6 @@ protected function setUp() '', false ); - $this->addressRepository = $this->getMock( \Magento\Customer\Model\ResourceModel\AddressRepository::class, [], @@ -123,7 +117,6 @@ protected function setUp() '', false ); - $this->customerMetadata = $this->getMockForAbstractClass( \Magento\Customer\Api\CustomerMetadataInterface::class, [], @@ -172,11 +165,15 @@ protected function setUp() \Magento\Customer\Api\Data\CustomerInterface::class, [], '', - false + true, + true, + true, + [ + '__toArray' + ] ); $this->collectionProcessorMock = $this->getMockBuilder(CollectionProcessorInterface::class) ->getMock(); - $this->model = new \Magento\Customer\Model\ResourceModel\CustomerRepository( $this->customerFactory, $this->customerSecureFactory, @@ -254,6 +251,11 @@ public function testSave() '', false ); + + $this->customer->expects($this->atLeastOnce()) + ->method('__toArray') + ->willReturn(['default_billing', 'default_shipping']); + $customerAttributesMetaData = $this->getMockForAbstractClass( \Magento\Framework\Api\CustomAttributesDataInterface::class, [], @@ -495,6 +497,11 @@ public function testSaveWithPasswordHash() 'getId' ] ); + + $this->customer->expects($this->atLeastOnce()) + ->method('__toArray') + ->willReturn(['default_billing', 'default_shipping']); + $customerModel = $this->getMock( \Magento\Customer\Model\Customer::class, [ diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Db/VersionControl/AddressSnapshotTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Db/VersionControl/AddressSnapshotTest.php index e2de4e7e7d5c4..861892624039c 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Db/VersionControl/AddressSnapshotTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Db/VersionControl/AddressSnapshotTest.php @@ -1,6 +1,6 @@ resource = $this->getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false); @@ -67,10 +78,18 @@ protected function setUp() false ); + $this->snapshotMock = $this->getMock( + \Magento\Framework\Model\ResourceModel\Db\VersionControl\Snapshot::class, + [], + [], + '', + false + ); + $transactionManagerMock = $this->getMock( \Magento\Framework\Model\ResourceModel\Db\TransactionManagerInterface::class ); - $transactionManagerMock->expects($this->once()) + $transactionManagerMock->expects($this->any()) ->method('start') ->willReturn($this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class)); $contextMock->expects($this->once()) @@ -86,10 +105,62 @@ protected function setUp() 'context' => $contextMock, 'groupManagement' => $this->groupManagement, 'customersFactory' => $this->customersFactory, + 'entitySnapshot' => $this->snapshotMock ] ); } + /** + * Test for save() method when we try to save entity with system's reserved ID. + * + * @return void + */ + public function testSaveWithReservedId() + { + $expectedId = 55; + $this->snapshotMock->expects($this->once())->method('isModified')->willReturn(true); + $this->snapshotMock->expects($this->once())->method('registerSnapshot')->willReturnSelf(); + + $this->groupModel->expects($this->any())->method('getId') + ->willReturn(\Magento\Customer\Model\Group::CUST_GROUP_ALL); + $this->groupModel->expects($this->any())->method('getData') + ->willReturn([]); + $this->groupModel->expects($this->any())->method('isSaveAllowed') + ->willReturn(true); + $this->groupModel->expects($this->any())->method('getStoredData') + ->willReturn([]); + $this->groupModel->expects($this->once())->method('setId') + ->with($expectedId); + + $dbAdapter = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'lastInsertId', + 'describeTable', + 'update', + 'select' + ] + ) + ->getMockForAbstractClass(); + $dbAdapter->expects($this->any())->method('describeTable')->willReturn([]); + $dbAdapter->expects($this->any())->method('update')->willReturnSelf(); + $dbAdapter->expects($this->once())->method('lastInsertId')->willReturn($expectedId); + $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class) + ->disableOriginalConstructor() + ->getMock(); + $dbAdapter->expects($this->any())->method('select')->willReturn($selectMock); + $selectMock->expects($this->any())->method('from')->willReturnSelf(); + $this->resource->expects($this->any())->method('getConnection')->willReturn($dbAdapter); + + $this->groupResourceModel->save($this->groupModel); + } + + /** + * Test for delete() method when we try to save entity with system's reserved ID. + * + * @return void + */ public function testDelete() { $dbAdapter = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class); diff --git a/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php b/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php index 48de976aec8cf..784f5eaa59f97 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php @@ -2,7 +2,7 @@ /** * Unit test for session \Magento\Customer\Model\Session * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Test\Unit\Model; diff --git a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php index dfeb2cb3612af..e70177d7955f2 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php @@ -1,6 +1,6 @@ 1, 'country_code' => 'US', 'group_id' => 1, - 'area_code' => Area::AREA_ADMIN, + 'area_code' => Area::AREA_ADMINHTML, 'is_vat_valid' => false, 'request_sucess' => false, 'valid_message' => '', diff --git a/app/code/Magento/Customer/Test/Unit/Observer/BeforeAddressSaveObserverTest.php b/app/code/Magento/Customer/Test/Unit/Observer/BeforeAddressSaveObserverTest.php index 0a4ea7b95c9d1..8589f4d28845f 100644 --- a/app/code/Magento/Customer/Test/Unit/Observer/BeforeAddressSaveObserverTest.php +++ b/app/code/Magento/Customer/Test/Unit/Observer/BeforeAddressSaveObserverTest.php @@ -1,6 +1,6 @@ [ - 'items' => [ - [ - 'lock_expires' => $lockExpirationDate - ], - ] - ] - ]; - $expectedDataSource = [ - 'data' => [ - 'items' => [ - [ - 'lock_expires' => $expectedResult, - ], - ] - ] - ]; - $dataSource = $this->component->prepareDataSource($dataSource); + $dataSource = $this->component->prepareDataSource($lockExpirationDate); - $this->assertEquals($expectedDataSource, $dataSource); + $this->assertEquals($expectedResult, $dataSource); } /** @@ -76,13 +58,77 @@ public function testPrepareDataSourceDataProvider() { return [ [ - 'lockExpirationDate' => date("F j, Y", strtotime('-1 days')), - 'expectedResult' => new \Magento\Framework\Phrase('Unlocked') + 'lockExpirationDate' => [ + 'data' => [ + 'items' => [['lock_expires' => null]], + ] + ], + 'expectedResult' => [ + 'data' => [ + 'items' => [ + [ + 'lock_expires' => new \Magento\Framework\Phrase('Unlocked') + ], + ] + ] + ] ], [ - 'lockExpirationDate' => date("F j, Y", strtotime('+1 days')), - 'expectedResult' => new \Magento\Framework\Phrase('Locked') - ] + 'lockExpirationDate' => [ + 'data' => [ + 'items' => [[]]//Non exist lock_expires data + ] + ], + 'expectedResult' => [ + 'data' => [ + 'items' => [ + [ + 'lock_expires' => new \Magento\Framework\Phrase('Unlocked') + ], + ] + ] + ] + ], + [ + 'lockExpirationDate' => [ + 'data' => [ + 'items' => [ + [ + 'lock_expires' => date("F j, Y", strtotime('-1 days')) + ], + ] + ] + ], + 'expectedResult' => [ + 'data' => [ + 'items' => [ + [ + 'lock_expires' => new \Magento\Framework\Phrase('Unlocked') + ], + ] + ] + ] + ], + [ + 'lockExpirationDate' => [ + 'data' => [ + 'items' => [ + [ + 'lock_expires' => date("F j, Y", strtotime('+1 days')) + ], + ] + ] + ], + 'expectedResult' => [ + 'data' => [ + 'items' => [ + [ + 'lock_expires' => new \Magento\Framework\Phrase('Locked') + ], + ] + ] + ] + ], ]; } } diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/ActionsTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/ActionsTest.php index 9d5c1364091ce..9af626ffaee7b 100644 --- a/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/ActionsTest.php +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Listing/Column/ActionsTest.php @@ -1,6 +1,6 @@ new \DateTime()) { - $item['lock_expires'] = __('Locked'); + if (array_key_exists('lock_expires', $item)) { + $lockExpires = new \DateTime($item['lock_expires']); + if ($lockExpires > new \DateTime()) { + $item['lock_expires'] = __('Locked'); + } else { + $item['lock_expires'] = __('Unlocked'); + } } else { $item['lock_expires'] = __('Unlocked'); } diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Column/Actions.php index 31ed8918e8651..f9abe542e4d55 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Column/Actions.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/etc/address_formats.xml b/app/code/Magento/Customer/etc/address_formats.xml index f501df2f3b63a..c4d74375c32d3 100644 --- a/app/code/Magento/Customer/etc/address_formats.xml +++ b/app/code/Magento/Customer/etc/address_formats.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/address_formats.xsd b/app/code/Magento/Customer/etc/address_formats.xsd index f5df16ffcc5ea..14d0ad4598054 100644 --- a/app/code/Magento/Customer/etc/address_formats.xsd +++ b/app/code/Magento/Customer/etc/address_formats.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/adminhtml/di.xml b/app/code/Magento/Customer/etc/adminhtml/di.xml index 08c9cb95efe66..cf2254307a9ed 100644 --- a/app/code/Magento/Customer/etc/adminhtml/di.xml +++ b/app/code/Magento/Customer/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/adminhtml/menu.xml b/app/code/Magento/Customer/etc/adminhtml/menu.xml index 31765fa89e8fe..eaa65dc280b00 100644 --- a/app/code/Magento/Customer/etc/adminhtml/menu.xml +++ b/app/code/Magento/Customer/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/adminhtml/routes.xml b/app/code/Magento/Customer/etc/adminhtml/routes.xml index 9f3b07f486025..4c68008dd1437 100644 --- a/app/code/Magento/Customer/etc/adminhtml/routes.xml +++ b/app/code/Magento/Customer/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Customer/etc/adminhtml/system.xml b/app/code/Magento/Customer/etc/adminhtml/system.xml index f542c2b6e0f5e..66c54016fc227 100644 --- a/app/code/Magento/Customer/etc/adminhtml/system.xml +++ b/app/code/Magento/Customer/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/cache.xml b/app/code/Magento/Customer/etc/cache.xml index 37d1a63f69a4e..553f1f6535d52 100644 --- a/app/code/Magento/Customer/etc/cache.xml +++ b/app/code/Magento/Customer/etc/cache.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/config.xml b/app/code/Magento/Customer/etc/config.xml index dae8447191833..ccee6914e4ea0 100644 --- a/app/code/Magento/Customer/etc/config.xml +++ b/app/code/Magento/Customer/etc/config.xml @@ -1,7 +1,7 @@ @@ -82,17 +82,15 @@ T: {{var telephone}} {{depend vat_id}}
    VAT: {{var vat_id}}{{/depend}}]]> F: {{var fax}}{{/depend}}| -{{depend vat_id}}
    VAT: {{var vat_id}}{{/depend}}|]]>
    +{{depend telephone}}T: {{var telephone}}|{{/depend}} +{{depend fax}}F: {{var fax}}|{{/depend}}| +{{depend vat_id}}VAT: {{var vat_id}}{{/depend}}|]]> diff --git a/app/code/Magento/Customer/etc/crontab.xml b/app/code/Magento/Customer/etc/crontab.xml index 472a49feb39fc..eda64cf2eca93 100644 --- a/app/code/Magento/Customer/etc/crontab.xml +++ b/app/code/Magento/Customer/etc/crontab.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index d8f320161ab06..225290f35c73f 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -1,7 +1,7 @@ @@ -51,6 +51,12 @@ type="Magento\Customer\Helper\View" /> + + + Magento\Customer\Model\Config\Share\Proxy @@ -307,6 +313,9 @@ + + + diff --git a/app/code/Magento/Customer/etc/email_templates.xml b/app/code/Magento/Customer/etc/email_templates.xml index 0d6b4d5877088..23fa73056b4c2 100644 --- a/app/code/Magento/Customer/etc/email_templates.xml +++ b/app/code/Magento/Customer/etc/email_templates.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/events.xml b/app/code/Magento/Customer/etc/events.xml index 45caa32d680c6..0e65ddca44924 100644 --- a/app/code/Magento/Customer/etc/events.xml +++ b/app/code/Magento/Customer/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/fieldset.xml b/app/code/Magento/Customer/etc/fieldset.xml index a43df71873475..b219305e3b9fa 100644 --- a/app/code/Magento/Customer/etc/fieldset.xml +++ b/app/code/Magento/Customer/etc/fieldset.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/frontend/di.xml b/app/code/Magento/Customer/etc/frontend/di.xml index 389d0eea246ea..4562acb00fe5b 100644 --- a/app/code/Magento/Customer/etc/frontend/di.xml +++ b/app/code/Magento/Customer/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/frontend/events.xml b/app/code/Magento/Customer/etc/frontend/events.xml index 5bb0ffe3cb7c2..75cc5f7c929dc 100644 --- a/app/code/Magento/Customer/etc/frontend/events.xml +++ b/app/code/Magento/Customer/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/frontend/page_types.xml b/app/code/Magento/Customer/etc/frontend/page_types.xml index bfcda34cc3111..77a0fb520bbd3 100644 --- a/app/code/Magento/Customer/etc/frontend/page_types.xml +++ b/app/code/Magento/Customer/etc/frontend/page_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/frontend/routes.xml b/app/code/Magento/Customer/etc/frontend/routes.xml index d448185245add..eb91d26288ab4 100644 --- a/app/code/Magento/Customer/etc/frontend/routes.xml +++ b/app/code/Magento/Customer/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Customer/etc/frontend/sections.xml b/app/code/Magento/Customer/etc/frontend/sections.xml index 83d6394cd0951..8d10da7036003 100644 --- a/app/code/Magento/Customer/etc/frontend/sections.xml +++ b/app/code/Magento/Customer/etc/frontend/sections.xml @@ -1,7 +1,7 @@ @@ -10,6 +10,7 @@ +
    diff --git a/app/code/Magento/Customer/etc/indexer.xml b/app/code/Magento/Customer/etc/indexer.xml index b48592cafbb20..1b831f778864c 100644 --- a/app/code/Magento/Customer/etc/indexer.xml +++ b/app/code/Magento/Customer/etc/indexer.xml @@ -1,7 +1,7 @@ @@ -11,7 +11,7 @@ Customer Grid Rebuild Customer grid index -
    diff --git a/app/code/Magento/Customer/etc/module.xml b/app/code/Magento/Customer/etc/module.xml index 085320e80d2c6..beffd59e01fcd 100644 --- a/app/code/Magento/Customer/etc/module.xml +++ b/app/code/Magento/Customer/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Customer/etc/mview.xml b/app/code/Magento/Customer/etc/mview.xml index 4f88d94f15ede..ebeaac0114158 100644 --- a/app/code/Magento/Customer/etc/mview.xml +++ b/app/code/Magento/Customer/etc/mview.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/sections.xsd b/app/code/Magento/Customer/etc/sections.xsd index 91a09129357bb..f2be0302db725 100644 --- a/app/code/Magento/Customer/etc/sections.xsd +++ b/app/code/Magento/Customer/etc/sections.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/validation.xml b/app/code/Magento/Customer/etc/validation.xml index b496a9345cb82..d06164942c7d4 100644 --- a/app/code/Magento/Customer/etc/validation.xml +++ b/app/code/Magento/Customer/etc/validation.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/webapi.xml b/app/code/Magento/Customer/etc/webapi.xml index 3a492e7370242..f78d9c01d16a3 100644 --- a/app/code/Magento/Customer/etc/webapi.xml +++ b/app/code/Magento/Customer/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/webapi_rest/di.xml b/app/code/Magento/Customer/etc/webapi_rest/di.xml index 045f16cc6d028..a9d21aea930d3 100644 --- a/app/code/Magento/Customer/etc/webapi_rest/di.xml +++ b/app/code/Magento/Customer/etc/webapi_rest/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/etc/webapi_soap/di.xml b/app/code/Magento/Customer/etc/webapi_soap/di.xml index ae882cfacba68..61cdd928de4f4 100644 --- a/app/code/Magento/Customer/etc/webapi_soap/di.xml +++ b/app/code/Magento/Customer/etc/webapi_soap/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/registration.php b/app/code/Magento/Customer/registration.php index a1f0064643132..4c1e81d195b19 100644 --- a/app/code/Magento/Customer/registration.php +++ b/app/code/Magento/Customer/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_cart.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_cart.xml index 965dc8fa4d3ad..1cb5d82323760 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_cart.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_cart.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_carts.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_carts.xml index c5ffdc4fbae7e..3fa611ebd6e88 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_carts.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_carts.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_edit.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_edit.xml index 7d13c2dcf9a02..dfa8379891ad2 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_edit.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_index.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_index.xml index 2bf05d10369f5..c6f3c3e2ead71 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_index.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_newsletter.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_newsletter.xml index 103b5ac2b38c4..10b4a31f5d963 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_newsletter.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_newsletter.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_orders.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_orders.xml index 031ae90eeab4c..e99d0a053eb0d 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_orders.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_orders.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_productreviews.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_productreviews.xml index 5b074b5095fef..671ef7ec0e7cc 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_productreviews.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_productreviews.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewcart.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewcart.xml index b44f04157ebe0..cc5d9e0da8225 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewcart.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewcart.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewwishlist.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewwishlist.xml index bad08a8f09737..8cd4ec724e3e3 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewwishlist.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_index_viewwishlist.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_online_index.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_online_index.xml index fb34ba65f7e26..1ae4259bc75fe 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_online_index.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_online_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/requirejs-config.js b/app/code/Magento/Customer/view/adminhtml/requirejs-config.js index 666193865f20a..589ece5b14104 100644 --- a/app/code/Magento/Customer/view/adminhtml/requirejs-config.js +++ b/app/code/Magento/Customer/view/adminhtml/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -14,4 +14,4 @@ var config = { observableInputs: 'Magento_Customer/edit/tab/js/addresses' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Customer/view/adminhtml/templates/edit/js.phtml b/app/code/Magento/Customer/view/adminhtml/templates/edit/js.phtml index e5450890826b1..49cc0c8c7395a 100644 --- a/app/code/Magento/Customer/view/adminhtml/templates/edit/js.phtml +++ b/app/code/Magento/Customer/view/adminhtml/templates/edit/js.phtml @@ -1,6 +1,6 @@ escapeJs($block->getMerchantVatNumberField()); ?>').value }; - new Ajax.Request('escapeUrl($block->getAjaxUrl()) ?>', { + new Ajax.Request('escapeJs($block->escapeUrl($block->getAjaxUrl())) ?>', { parameters: params, onSuccess: function(response) { - var result = ''; + var result = 'escapeJs($block->escapeHtml(__('Error during VAT Number verification.'))) ?>'; try { if (response.responseText.isJSON()) { response = response.responseText.evalJSON(); diff --git a/app/code/Magento/Customer/view/adminhtml/templates/tab/cart.phtml b/app/code/Magento/Customer/view/adminhtml/templates/tab/cart.phtml index f8ca555c2ada6..e456e02f0b10f 100644 --- a/app/code/Magento/Customer/view/adminhtml/templates/tab/cart.phtml +++ b/app/code/Magento/Customer/view/adminhtml/templates/tab/cart.phtml @@ -1,6 +1,6 @@ escapeJs($listType) ?>', { - urlFetch: 'escapeUrl($block->getUrl('customer/cart_product_composite_cart/configure', $params)) ?>', - urlConfirm: 'escapeUrl($block->getUrl('customer/cart_product_composite_cart/update', $params)) ?>' + urlFetch: 'escapeJs($block->escapeUrl($block->getUrl('customer/cart_product_composite_cart/configure', $params))) ?>', + urlConfirm: 'escapeJs($block->escapeUrl($block->getUrl('customer/cart_product_composite_cart/update', $params))) ?>' } ); diff --git a/app/code/Magento/Customer/view/adminhtml/templates/tab/newsletter.phtml b/app/code/Magento/Customer/view/adminhtml/templates/tab/newsletter.phtml index d18dc9a08398f..fcb86ae16ff41 100644 --- a/app/code/Magento/Customer/view/adminhtml/templates/tab/newsletter.phtml +++ b/app/code/Magento/Customer/view/adminhtml/templates/tab/newsletter.phtml @@ -1,6 +1,6 @@ getStoreCreateDate(); ?>
    - + escapeHtml(__('Personal Information')) ?>
    getChildHtml(); ?> - + - + - + - + - + - + - + - +
    escapeHtml(__('Last Logged In:')) ?> escapeHtml($lastLoginDateAdmin) ?> (escapeHtml($block->getCurrentStatus()) ?>)
    getStoreLastLoginDateTimezone()) ?>escapeHtml(__('Last Logged In (%1):', $block->getStoreLastLoginDateTimezone())) ?> escapeHtml($lastLoginDateStore) ?> (escapeHtml($block->getCurrentStatus()) ?>)
    escapeHtml(__('Account Lock:')) ?> escapeHtml($block->getAccountLock()) ?>
    escapeHtml(__('Confirmed email:')) ?> escapeHtml($block->getIsConfirmedStatus()) ?>
    escapeHtml(__('Account Created:')) ?> escapeHtml($createDateAdmin) ?>
    getStoreCreateDateTimezone()) ?>escapeHtml(__('Account Created on (%1):', $block->getStoreCreateDateTimezone())) ?> escapeHtml($createDateStore) ?>
    escapeHtml(__('Account Created in:')) ?> escapeHtml($block->getCreatedInStore()) ?>
    escapeHtml(__('Customer Group:')) ?> escapeHtml($block->getGroupName()) ?>
    -
    + escapeHtml(__('Default Billing Address')) ?>
    getBillingAddressHtml() ?>
    diff --git a/app/code/Magento/Customer/view/adminhtml/templates/tab/view/sales.phtml b/app/code/Magento/Customer/view/adminhtml/templates/tab/view/sales.phtml index 4aef50934a588..9a00e313a16ba 100644 --- a/app/code/Magento/Customer/view/adminhtml/templates/tab/view/sales.phtml +++ b/app/code/Magento/Customer/view/adminhtml/templates/tab/view/sales.phtml @@ -1,6 +1,6 @@ isSingleStoreMode();
    - + escapeHtml(__('Sales Statistics')) ?>
    - - - + + + - - + + - + diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml index 05b419983d513..4b92177286b62 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_online_grid.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_online_grid.xml index 2dc9e89090c4c..4cb3547cb76a7 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_online_grid.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_online_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js b/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js index d6fc60b5fb932..9b368adcbe665 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js +++ b/app/code/Magento/Customer/view/adminhtml/web/edit/post-wrapper.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Customer/view/adminhtml/web/edit/tab/js/addresses.js b/app/code/Magento/Customer/view/adminhtml/web/edit/tab/js/addresses.js index a3e04fc43fc40..7242dc945178d 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/edit/tab/js/addresses.js +++ b/app/code/Magento/Customer/view/adminhtml/web/edit/tab/js/addresses.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -563,4 +563,4 @@ define([ observableInputs: $.mage.observableInputs, dataItemDeleteButton: $.mage.dataItemDeleteButton }; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/bootstrap/customer-post-action.js b/app/code/Magento/Customer/view/adminhtml/web/js/bootstrap/customer-post-action.js index 7ea9247ecd94b..661c4e3d471c3 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/bootstrap/customer-post-action.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/bootstrap/customer-post-action.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 41ffb74184bad..ab5a89f9d3571 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -1,7 +1,7 @@ @@ -98,7 +98,11 @@ number select + Magento_Ui/js/form/element/website customer + + ${ $.provider }:data.customer.entity_id + true @@ -256,6 +260,10 @@ Send Welcome Email From number select + customer + + ${ $.provider }:data.customer.store_id + @@ -369,10 +377,14 @@ text select + Magento_Ui/js/form/element/country address true + + ${ $.provider }:data.customer.website_id + diff --git a/app/code/Magento/Customer/view/frontend/email/account_new.html b/app/code/Magento/Customer/view/frontend/email/account_new.html index 9d67e26e8e715..dac8e1ce57505 100644 --- a/app/code/Magento/Customer/view/frontend/email/account_new.html +++ b/app/code/Magento/Customer/view/frontend/email/account_new.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html b/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html index 193a1faed662d..5432956e8f03f 100644 --- a/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html +++ b/app/code/Magento/Customer/view/frontend/email/account_new_confirmation.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/account_new_confirmed.html b/app/code/Magento/Customer/view/frontend/email/account_new_confirmed.html index 6e94fbdcc7807..b50c944c18b46 100644 --- a/app/code/Magento/Customer/view/frontend/email/account_new_confirmed.html +++ b/app/code/Magento/Customer/view/frontend/email/account_new_confirmed.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/account_new_no_password.html b/app/code/Magento/Customer/view/frontend/email/account_new_no_password.html index 14cd8e98f8bfe..1c5371bd4868b 100644 --- a/app/code/Magento/Customer/view/frontend/email/account_new_no_password.html +++ b/app/code/Magento/Customer/view/frontend/email/account_new_no_password.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/change_email.html b/app/code/Magento/Customer/view/frontend/email/change_email.html index ab24368c02239..09d1537e1cc07 100644 --- a/app/code/Magento/Customer/view/frontend/email/change_email.html +++ b/app/code/Magento/Customer/view/frontend/email/change_email.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html b/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html index d2ca4d4cae0a2..23280b2822b48 100644 --- a/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html +++ b/app/code/Magento/Customer/view/frontend/email/change_email_and_password.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/password_new.html b/app/code/Magento/Customer/view/frontend/email/password_new.html index 12c5a30ddf103..f5c2d87128300 100644 --- a/app/code/Magento/Customer/view/frontend/email/password_new.html +++ b/app/code/Magento/Customer/view/frontend/email/password_new.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/password_reset.html b/app/code/Magento/Customer/view/frontend/email/password_reset.html index 061e640810705..a255e2f99e575 100644 --- a/app/code/Magento/Customer/view/frontend/email/password_reset.html +++ b/app/code/Magento/Customer/view/frontend/email/password_reset.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html index a07b36c148005..efdd89bbec720 100644 --- a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html +++ b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml index a96dfcd86e542..12849c5b0762b 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml @@ -1,7 +1,7 @@ @@ -9,24 +9,45 @@ - - + + + account-nav + + - Account Dashboard - customer/account - - - - - Account Information - customer/account/edit - - - - - Address Book - customer/address + nav items + + + Account Dashboard + customer/account + 250 + + + + + 200 + + + + + Address Book + customer/address + 190 + + + + + Account Information + customer/account/edit + 180 + + + + + 130 + + diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_confirmation.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_confirmation.xml index 5bf52253badd7..c2d7dc01dbbea 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_confirmation.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_confirmation.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml index 8eaba5c75fe1d..8a42132dd01fd 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_create.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_createpassword.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_createpassword.xml index 298ad6e9c3968..878fd56999045 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_createpassword.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_createpassword.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml index aa09fecc68170..452d98821105f 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_forgotpassword.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_forgotpassword.xml index e33da515e150a..a39f15c201c65 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_forgotpassword.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_forgotpassword.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml index c3a255192eb9b..6e738ac2980be 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_login.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_login.xml index 32b471dff8b33..e7c157acb1bfb 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_login.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_login.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_logoutsuccess.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_logoutsuccess.xml index 93b522c90dc60..d76363eaffb05 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_logoutsuccess.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_logoutsuccess.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_address_form.xml b/app/code/Magento/Customer/view/frontend/layout/customer_address_form.xml index 46bea31094523..67ab9768157e5 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_address_form.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_address_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_address_index.xml b/app/code/Magento/Customer/view/frontend/layout/customer_address_index.xml index 8706ba25c5691..42f7b5ea38a69 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_address_index.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_address_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Customer/view/frontend/layout/default.xml b/app/code/Magento/Customer/view/frontend/layout/default.xml index 50580f73a9d31..d80391c4973b6 100644 --- a/app/code/Magento/Customer/view/frontend/layout/default.xml +++ b/app/code/Magento/Customer/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ @@ -11,6 +11,7 @@ My Account + 110 diff --git a/app/code/Magento/Customer/view/frontend/requirejs-config.js b/app/code/Magento/Customer/view/frontend/requirejs-config.js index 53f12373bfd92..99442b69ac04e 100644 --- a/app/code/Magento/Customer/view/frontend/requirejs-config.js +++ b/app/code/Magento/Customer/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -10,7 +10,8 @@ var config = { address: 'Magento_Customer/address', changeEmailPassword: 'Magento_Customer/change-email-password', passwordStrengthIndicator: 'Magento_Customer/js/password-strength-indicator', - zxcvbn: 'Magento_Customer/js/zxcvbn' + zxcvbn: 'Magento_Customer/js/zxcvbn', + addressValidation: 'Magento_Customer/js/addressValidation' } } }; diff --git a/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml b/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml index 2b62b1f6fb7aa..bcf0cc92bc912 100644 --- a/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml @@ -1,6 +1,6 @@ getJsLayout();?> }, "*": { - "Magento_Ui/js/block-loader": "escapeUrl($block->getViewFileUrl('images/loader-1.gif')); ?>" + "Magento_Ui/js/block-loader": "escapeJs($block->escapeUrl($block->getViewFileUrl('images/loader-1.gif'))); ?>" } } diff --git a/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml b/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml index d215028698e7e..904362e50324b 100644 --- a/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/account/customer.phtml @@ -1,11 +1,11 @@ customerLoggedIn()): ?>
  • @@ -21,7 +21,7 @@ class="action switch" tabindex="-1" data-action="customer-menu-toggle"> - + escapeHtml(__('Change'))?> diff --git a/app/code/Magento/Customer/view/frontend/templates/newcustomer.phtml b/app/code/Magento/Customer/view/frontend/templates/newcustomer.phtml index 7bfa236eabb95..5769b1cae37f0 100644 --- a/app/code/Magento/Customer/view/frontend/templates/newcustomer.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/newcustomer.phtml @@ -1,6 +1,6 @@ getRegistration()->isAllowed()): ?>
    - + escapeHtml(__('New Customers')) ?>
    -

    +

    escapeHtml(__('Creating an account has many benefits: check out faster, keep more than one address, track orders and more.')) ?>

    diff --git a/app/code/Magento/Customer/view/frontend/templates/widget/dob.phtml b/app/code/Magento/Customer/view/frontend/templates/widget/dob.phtml index 727dc43750ae5..9480917e40c07 100644 --- a/app/code/Magento/Customer/view/frontend/templates/widget/dob.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/widget/dob.phtml @@ -1,6 +1,6 @@
    - +
    - isRequired()):?> class="validate-select" data-validate="{required:true}"> getGenderOptions(); ?> getGender();?> - +
    diff --git a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml index 57dcdbb308568..389f79e2573fe 100644 --- a/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/widget/name.phtml @@ -1,6 +1,6 @@ showSuffix(); getNoWrap()): ?>
    @@ -56,7 +56,7 @@ $suffix = $block->showSuffix(); class="escapeHtmlAttr($block->getAttributeValidationClass('prefix')) ?>" isPrefixRequired()) echo ' data-validate="{required:true}"' ?> > getPrefixOptions() as $_option): ?> @@ -126,7 +126,7 @@ $suffix = $block->showSuffix(); class="escapeHtmlAttr($block->getAttributeValidationClass('suffix')) ?>" isSuffixRequired()) echo ' data-validate="{required:true}"' ?>> getSuffixOptions() as $_option): ?> diff --git a/app/code/Magento/Customer/view/frontend/templates/widget/taxvat.phtml b/app/code/Magento/Customer/view/frontend/templates/widget/taxvat.phtml index 0463d33ad6e2d..9bb7b6a7b6e9b 100644 --- a/app/code/Magento/Customer/view/frontend/templates/widget/taxvat.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/widget/taxvat.phtml @@ -1,6 +1,6 @@
    - +
    - isRequired()) echo ' data-validate="{required:true}"' ?>> + isRequired()) echo ' data-validate="{required:true}"' ?>>
    diff --git a/app/code/Magento/Customer/view/frontend/web/address.js b/app/code/Magento/Customer/view/frontend/web/address.js index 78443af9a3ab2..043ad27194a2c 100644 --- a/app/code/Magento/Customer/view/frontend/web/address.js +++ b/app/code/Magento/Customer/view/frontend/web/address.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true, jquery:true*/ @@ -77,4 +77,4 @@ define([ }); return $.mage.address; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Customer/view/frontend/web/change-email-password.js b/app/code/Magento/Customer/view/frontend/web/change-email-password.js index 26b565e213942..a3ed0893817db 100644 --- a/app/code/Magento/Customer/view/frontend/web/change-email-password.js +++ b/app/code/Magento/Customer/view/frontend/web/change-email-password.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true expr:true*/ diff --git a/app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js b/app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js index 46e9067034075..3bdface5b6c81 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js +++ b/app/code/Magento/Customer/view/frontend/web/js/action/check-email-availability.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define( diff --git a/app/code/Magento/Customer/view/frontend/web/js/action/login.js b/app/code/Magento/Customer/view/frontend/web/js/action/login.js index 56a1434a17263..a7afac3e4560a 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/action/login.js +++ b/app/code/Magento/Customer/view/frontend/web/js/action/login.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global define*/ diff --git a/app/code/Magento/Customer/view/frontend/web/js/addressValidation.js b/app/code/Magento/Customer/view/frontend/web/js/addressValidation.js new file mode 100644 index 0000000000000..1e6ef42014545 --- /dev/null +++ b/app/code/Magento/Customer/view/frontend/web/js/addressValidation.js @@ -0,0 +1,43 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/*jshint browser:true jquery:true*/ +define([ + 'jquery', + 'jquery/ui', + 'validation' +], function ($) { + 'use strict'; + + $.widget('mage.addressValidation', { + options: { + selectors: { + button: '[data-action=save-address]' + } + }, + + /** + * Validation creation + * @protected + */ + _create: function () { + var button = $(this.options.selectors.button, this.element); + + this.element.validation({ + + /** + * Submit Handler + * @param {Element} form - address form + */ + submitHandler: function (form) { + + button.attr('disabled', true); + form.submit(); + } + }); + } + }); + + return $.mage.addressValidation; +}); diff --git a/app/code/Magento/Customer/view/frontend/web/js/checkout-balance.js b/app/code/Magento/Customer/view/frontend/web/js/checkout-balance.js index 430106f6b9083..777279e212123 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/checkout-balance.js +++ b/app/code/Magento/Customer/view/frontend/web/js/checkout-balance.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ @@ -36,4 +36,4 @@ define([ }); return $.mage.checkoutBalance; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index a3ef770fffdf4..a017eba4c7977 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/address-list.js b/app/code/Magento/Customer/view/frontend/web/js/model/address-list.js index f5a118fa90da6..3c8e593a411c4 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/model/address-list.js +++ b/app/code/Magento/Customer/view/frontend/web/js/model/address-list.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global define*/ @@ -12,4 +12,4 @@ define( "use strict"; return ko.observableArray(defaultProvider.getAddressItems()); } -); \ No newline at end of file +); diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/authentication-popup.js b/app/code/Magento/Customer/view/frontend/web/js/model/authentication-popup.js index 95092b758e963..9f0b13414a736 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/model/authentication-popup.js +++ b/app/code/Magento/Customer/view/frontend/web/js/model/authentication-popup.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js index f6740550efca6..771dc1446cf6c 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js +++ b/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global define*/ @@ -11,11 +11,13 @@ define( ], function($, ko, address) { "use strict"; + var isLoggedIn = ko.observable(window.isCustomerLoggedIn); + return { getAddressItems: function() { var items = []; - if (isLoggedIn) { + if (isLoggedIn()) { var customerData = window.customerData; if (Object.keys(customerData).length) { $.each(customerData.addresses, function (key, item) { @@ -23,8 +25,9 @@ define( }); } } + return items; } } } -); \ No newline at end of file +); diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/customer.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer.js index 61e9a3fdc20e3..fab10dc1204dd 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/model/customer.js +++ b/app/code/Magento/Customer/view/frontend/web/js/model/customer.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global define*/ diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js index 30fbef98fd39a..601fd09a056c4 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js +++ b/app/code/Magento/Customer/view/frontend/web/js/model/customer/address.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ @@ -10,11 +10,17 @@ define([], function() { * Returns new address object */ return function (addressData) { + var regionId; + + if (addressData.region['region_id'] && addressData.region['region_id'] !== '0') { + regionId = addressData.region['region_id'] + ''; + } + return { customerAddressId: addressData.id, email: addressData.email, countryId: addressData.country_id, - regionId: addressData.region_id, + regionId: regionId, regionCode: addressData.region.region_code, region: addressData.region.region, customerId: addressData.customer_id, diff --git a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js index 298af46103ec0..5131e251f8f6a 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js +++ b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Customer/view/frontend/web/js/section-config.js b/app/code/Magento/Customer/view/frontend/web/js/section-config.js index a4b4a2cc3ba20..f503fd291d333 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/section-config.js +++ b/app/code/Magento/Customer/view/frontend/web/js/section-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define(['underscore'], function (_) { diff --git a/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js b/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js index 649238a81d1f7..98914a1fa2e60 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js +++ b/app/code/Magento/Customer/view/frontend/web/js/view/authentication-popup.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ @@ -69,19 +69,24 @@ define( }, /** Provide login action */ - login: function (loginForm) { + login: function (formUiElement, event) { var loginData = {}, - formDataArray = $(loginForm).serializeArray(); + formElement = $(event.currentTarget), + formDataArray = formElement.serializeArray(); + + event.stopPropagation(); formDataArray.forEach(function (entry) { loginData[entry.name] = entry.value; }); - if ($(loginForm).validation() && - $(loginForm).validation('isValid') + if (formElement.validation() && + formElement.validation('isValid') ) { this.isLoading(true); - loginAction(loginData, null, false); + loginAction(loginData); } + + return false; } }); } diff --git a/app/code/Magento/Customer/view/frontend/web/js/view/customer.js b/app/code/Magento/Customer/view/frontend/web/js/view/customer.js index e85c33ae96e42..ca8dc96bd6fe0 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/view/customer.js +++ b/app/code/Magento/Customer/view/frontend/web/js/view/customer.js @@ -1,5 +1,5 @@ /** -* Copyright © 2016 Magento. All rights reserved. +* Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Customer/view/frontend/web/template/authentication-popup.html b/app/code/Magento/Customer/view/frontend/web/template/authentication-popup.html index 1ff64fffe2036..ad3e169337d16 100644 --- a/app/code/Magento/Customer/view/frontend/web/template/authentication-popup.html +++ b/app/code/Magento/Customer/view/frontend/web/template/authentication-popup.html @@ -1,6 +1,6 @@ @@ -50,7 +50,7 @@
    - + escapeHtml(__("Rating isn't Available")) ?> diff --git a/app/code/Magento/Review/view/adminhtml/templates/rss/grid/link.phtml b/app/code/Magento/Review/view/adminhtml/templates/rss/grid/link.phtml index 763d8e8ed29fb..be9715020265e 100644 --- a/app/code/Magento/Review/view/adminhtml/templates/rss/grid/link.phtml +++ b/app/code/Magento/Review/view/adminhtml/templates/rss/grid/link.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Review/view/adminhtml/web/js/rating.js b/app/code/Magento/Review/view/adminhtml/web/js/rating.js index 3c2d41d2f3337..5525a8c517b37 100644 --- a/app/code/Magento/Review/view/adminhtml/web/js/rating.js +++ b/app/code/Magento/Review/view/adminhtml/web/js/rating.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -52,4 +52,4 @@ define([ } }); -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Review/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Review/view/frontend/layout/catalog_product_view.xml index ded60d5cf6e42..c3809ba564e8b 100644 --- a/app/code/Magento/Review/view/frontend/layout/catalog_product_view.xml +++ b/app/code/Magento/Review/view/frontend/layout/catalog_product_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/checkout_cart_configure.xml b/app/code/Magento/Review/view/frontend/layout/checkout_cart_configure.xml index 022e98eebb49c..9225835461434 100644 --- a/app/code/Magento/Review/view/frontend/layout/checkout_cart_configure.xml +++ b/app/code/Magento/Review/view/frontend/layout/checkout_cart_configure.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/customer_account.xml b/app/code/Magento/Review/view/frontend/layout/customer_account.xml index 9de10e43fa4d1..518957166a2fc 100644 --- a/app/code/Magento/Review/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Review/view/frontend/layout/customer_account.xml @@ -1,17 +1,18 @@ - + review/customer My Product Reviews + 50 diff --git a/app/code/Magento/Review/view/frontend/layout/customer_account_index.xml b/app/code/Magento/Review/view/frontend/layout/customer_account_index.xml index 6b5631f6e15fd..fb902cb7f3cdc 100644 --- a/app/code/Magento/Review/view/frontend/layout/customer_account_index.xml +++ b/app/code/Magento/Review/view/frontend/layout/customer_account_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/review_customer_index.xml b/app/code/Magento/Review/view/frontend/layout/review_customer_index.xml index 931ee5a768839..ca67c4122230f 100644 --- a/app/code/Magento/Review/view/frontend/layout/review_customer_index.xml +++ b/app/code/Magento/Review/view/frontend/layout/review_customer_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/review_customer_view.xml b/app/code/Magento/Review/view/frontend/layout/review_customer_view.xml index 71c22043df658..e9263c076f522 100644 --- a/app/code/Magento/Review/view/frontend/layout/review_customer_view.xml +++ b/app/code/Magento/Review/view/frontend/layout/review_customer_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/review_product_form_component.xml b/app/code/Magento/Review/view/frontend/layout/review_product_form_component.xml index 13e50e6fdae4b..d8dcf26153b2c 100644 --- a/app/code/Magento/Review/view/frontend/layout/review_product_form_component.xml +++ b/app/code/Magento/Review/view/frontend/layout/review_product_form_component.xml @@ -1,7 +1,7 @@ @@ -19,4 +19,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Review/view/frontend/layout/review_product_list.xml b/app/code/Magento/Review/view/frontend/layout/review_product_list.xml index 0970aaf522e72..d1264612c52f0 100644 --- a/app/code/Magento/Review/view/frontend/layout/review_product_list.xml +++ b/app/code/Magento/Review/view/frontend/layout/review_product_list.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/review_product_listajax.xml b/app/code/Magento/Review/view/frontend/layout/review_product_listajax.xml index 5f6a0ebbb9759..e636d601543d2 100644 --- a/app/code/Magento/Review/view/frontend/layout/review_product_listajax.xml +++ b/app/code/Magento/Review/view/frontend/layout/review_product_listajax.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/review_product_view.xml b/app/code/Magento/Review/view/frontend/layout/review_product_view.xml index 60c65b84e9588..e80bc26f164d3 100644 --- a/app/code/Magento/Review/view/frontend/layout/review_product_view.xml +++ b/app/code/Magento/Review/view/frontend/layout/review_product_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/layout/wishlist_index_configure.xml b/app/code/Magento/Review/view/frontend/layout/wishlist_index_configure.xml index 022e98eebb49c..9225835461434 100644 --- a/app/code/Magento/Review/view/frontend/layout/wishlist_index_configure.xml +++ b/app/code/Magento/Review/view/frontend/layout/wishlist_index_configure.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Review/view/frontend/templates/customer/list.phtml b/app/code/Magento/Review/view/frontend/templates/customer/list.phtml index 578f8d19c22b5..2dfee842171fb 100644 --- a/app/code/Magento/Review/view/frontend/templates/customer/list.phtml +++ b/app/code/Magento/Review/view/frontend/templates/customer/list.phtml @@ -1,6 +1,6 @@ getReviews() && count($block->getReviews())): ?>
  • escapeHtml(__('Web Site')) ?>escapeHtml(__('Store')) ?>escapeHtml(__('Store View')) ?> escapeHtml(__('Lifetime Sales')) ?>escapeHtml(__('Average Sale')) ?>
    escapeHtml(__('All Store Views')) ?> escapeHtml($block->formatCurrency($block->getTotals()->getBaseLifetime())) ?> escapeHtml($block->formatCurrency($block->getTotals()->getAvgsale())) ?>
    - + - - - - + + + + @@ -33,19 +33,19 @@ - - @@ -59,12 +59,12 @@ -
    +
    escapeHtml(__('You have submitted no reviews.')) ?>
    diff --git a/app/code/Magento/Review/view/frontend/templates/customer/recent.phtml b/app/code/Magento/Review/view/frontend/templates/customer/recent.phtml index b232b832b86ac..a1a2675092d62 100644 --- a/app/code/Magento/Review/view/frontend/templates/customer/recent.phtml +++ b/app/code/Magento/Review/view/frontend/templates/customer/recent.phtml @@ -1,6 +1,6 @@ getReviews() && count($block->getReviews())): ?>
    - - + escapeHtml(__('My Recent Reviews')) ?> + escapeHtml(__('View All')) ?>
      @@ -22,7 +22,7 @@ getSum()): ?> getSum() / $_review->getCount() ?>
      - : + escapeHtml(__('Rating')) ?>:
      escapeHtml($rating); ?>%
      diff --git a/app/code/Magento/Review/view/frontend/templates/customer/view.phtml b/app/code/Magento/Review/view/frontend/templates/customer/view.phtml index 9937fce922f54..2198a42fdf94e 100644 --- a/app/code/Magento/Review/view/frontend/templates/customer/view.phtml +++ b/app/code/Magento/Review/view/frontend/templates/customer/view.phtml @@ -1,6 +1,6 @@ getProductData();

      escapeHtml($product->getName()) ?>

      getRating() && $block->getRating()->getSize()): ?> - + escapeHtml(__('Average Customer Rating:')) ?> getReviewsSummaryHtml($product) ?>
      @@ -31,7 +31,7 @@ $product = $block->getProductData();
      getRating() && $block->getRating()->getSize()): ?>
      - + escapeHtml(__('Your Review')); ?>
      getRating() as $_rating): ?> @@ -53,13 +53,13 @@ $product = $block->getProductData();
      escapeHtml($block->getReviewData()->getTitle()) ?>
      escapeHtml($block->getReviewData()->getDetail())) ?>
      - ' . $block->dateFormat($block->getReviewData()->getCreatedAt()) . '') ?> + escapeHtml(__('Submitted on %1', ''), ['time']) ?>
      diff --git a/app/code/Magento/Review/view/frontend/templates/detailed.phtml b/app/code/Magento/Review/view/frontend/templates/detailed.phtml index 72bd4fcaca377..484a36f4bb2f5 100644 --- a/app/code/Magento/Review/view/frontend/templates/detailed.phtml +++ b/app/code/Magento/Review/view/frontend/templates/detailed.phtml @@ -1,6 +1,6 @@ getSize()): ?>
    escapeHtml(__('Product Reviews')) ?>
    escapeHtml(__('Created')) ?>escapeHtml(__('Product Name')) ?>escapeHtml(__('Rating')) ?>escapeHtml(__('Review')) ?>  
    getSum()): ?>
    - : -
    - getSum() / $_review->getCount()) ?>% + escapeHtml(__('Rating')) ?>: +
    + getSum() / (int)$_review->getCount()) ?>%
    + helper('Magento\Review\Helper\Data')->getDetailHtml($_review->getDetail()) ?> + - + escapeHtml(__('See Details')) ?>
    - + getSummary()): ?> - +
    escapeHtml(__('Ratings Review Summary')); ?>
    escapeHtml($_rating->getRatingCode())) ?>escapeHtml(__($_rating->getRatingCode())) ?>
    diff --git a/app/code/Magento/Review/view/frontend/templates/empty.phtml b/app/code/Magento/Review/view/frontend/templates/empty.phtml index 7029fe75ca75a..6fd2e388c889f 100644 --- a/app/code/Magento/Review/view/frontend/templates/empty.phtml +++ b/app/code/Magento/Review/view/frontend/templates/empty.phtml @@ -1,9 +1,11 @@ -

    +

    escapeHtml(__('Be the first to review this product')) ?>

    diff --git a/app/code/Magento/Review/view/frontend/templates/form.phtml b/app/code/Magento/Review/view/frontend/templates/form.phtml index 611416586ddf8..b96e1ea01f744 100644 --- a/app/code/Magento/Review/view/frontend/templates/form.phtml +++ b/app/code/Magento/Review/view/frontend/templates/form.phtml @@ -1,6 +1,6 @@
    -
    +
    escapeHtml(__('Write Your Own Review')) ?>
    getAllowWriteReviewFlag()): ?> getBlockHtml('formkey'); ?> getChildHtml('form_fields_before')?> -
    - escapeHtml($block->getProductInfo()->getName()) ?>
    +
    + escapeHtml(__("You're reviewing:")); ?>escapeHtml($block->getProductInfo()->getName()) ?>
    getRatings() && $block->getRatings()->getSize()): ?>
    -
    + escapeHtml(__('Your Rating')) ?>
    getRatings() as $_rating): ?> @@ -40,9 +40,9 @@ @@ -55,19 +55,19 @@
    - +
    - +
    - +
    @@ -75,7 +75,7 @@
    - +
    @@ -92,7 +92,7 @@
    - Sign in or create an account', $block->getLoginLink(), $block->getRegisterUrl()) ?> + escapeHtml(__('Only registered users can write reviews. Please Sign in or create an account', $block->getLoginLink(), $block->getRegisterUrl()), ['a']) ?>
    diff --git a/app/code/Magento/Review/view/frontend/templates/helper/summary.phtml b/app/code/Magento/Review/view/frontend/templates/helper/summary.phtml index cc5d8a0b6aed9..ca08a5f2cf8c0 100644 --- a/app/code/Magento/Review/view/frontend/templates/helper/summary.phtml +++ b/app/code/Magento/Review/view/frontend/templates/helper/summary.phtml @@ -1,6 +1,6 @@ getReviewsUrl() . '#review-form'; getDisplayIfEmpty()): ?> diff --git a/app/code/Magento/Review/view/frontend/templates/helper/summary_short.phtml b/app/code/Magento/Review/view/frontend/templates/helper/summary_short.phtml index 14650e7b0e0d1..1c23b33c0551c 100644 --- a/app/code/Magento/Review/view/frontend/templates/helper/summary_short.phtml +++ b/app/code/Magento/Review/view/frontend/templates/helper/summary_short.phtml @@ -1,6 +1,6 @@ getReviewsUrl() . '#review-form'; getDisplayIfEmpty()): ?> diff --git a/app/code/Magento/Review/view/frontend/templates/product/view/count.phtml b/app/code/Magento/Review/view/frontend/templates/product/view/count.phtml index fb7741a5ea2d9..1cc3e9f5ce939 100644 --- a/app/code/Magento/Review/view/frontend/templates/product/view/count.phtml +++ b/app/code/Magento/Review/view/frontend/templates/product/view/count.phtml @@ -1,12 +1,12 @@ - + escapeHtml(__('%1 Review(s)', $count)) ?> diff --git a/app/code/Magento/Review/view/frontend/templates/product/view/list.phtml b/app/code/Magento/Review/view/frontend/templates/product/view/list.phtml index 9eb4fd10fece1..60a4fdcdf3edc 100644 --- a/app/code/Magento/Review/view/frontend/templates/product/view/list.phtml +++ b/app/code/Magento/Review/view/frontend/templates/product/view/list.phtml @@ -1,6 +1,6 @@ getDateFormat() ?: \IntlDateFormatter::SHORT;
    - + escapeHtml(__('Customer Reviews')) ?>
    @@ -45,11 +45,11 @@ $format = $block->getDateFormat() ?: \IntlDateFormatter::SHORT;

    - + escapeHtml(__('Review by'))?>

    - + escapeHtml(__('Posted on')) ?>

    diff --git a/app/code/Magento/Review/view/frontend/templates/product/view/other.phtml b/app/code/Magento/Review/view/frontend/templates/product/view/other.phtml index 3c8d626b31748..8b0fe6193e53d 100644 --- a/app/code/Magento/Review/view/frontend/templates/product/view/other.phtml +++ b/app/code/Magento/Review/view/frontend/templates/product/view/other.phtml @@ -1,6 +1,6 @@ getProduct(); ?> diff --git a/app/code/Magento/Review/view/frontend/templates/redirect.phtml b/app/code/Magento/Review/view/frontend/templates/redirect.phtml index e90fb50a7b42f..5319b92490ae8 100644 --- a/app/code/Magento/Review/view/frontend/templates/redirect.phtml +++ b/app/code/Magento/Review/view/frontend/templates/redirect.phtml @@ -1,6 +1,6 @@ escapeUrl($block->getProductReviewUrl()); ?>" + "productReviewUrl": "escapeJs($block->escapeUrl($block->getProductReviewUrl())); ?>", + "reviewsTabSelector": "#tab-label-reviews" } } } diff --git a/app/code/Magento/Review/view/frontend/templates/view.phtml b/app/code/Magento/Review/view/frontend/templates/view.phtml index f44d31d63f7b7..47941e1aaeb3b 100644 --- a/app/code/Magento/Review/view/frontend/templates/view.phtml +++ b/app/code/Magento/Review/view/frontend/templates/view.phtml @@ -1,6 +1,6 @@ getProductData()->getId()): ?>
    -

    +

    escapeHtml(__('Review Details')) ?>

    getImage($block->getProductData(), 'product_base_image', ['class' => 'product-image'])->toHtml(); ?> getRating() && $block->getRating()->getSize()): ?> -

    :

    +

    escapeHtml(__('Average Customer Rating')) ?>:

    getReviewsSummaryHtml($block->getProductData()) ?>

    escapeHtml($block->getProductData()->getName()) ?>

    getRating() && $block->getRating()->getSize()): ?> -

    +

    escapeHtml(__('Product Rating:')) ?>

    - + getRating() as $_rating): ?> getPercent()): ?> - +
    escapeHtml(__('Product Rating')); ?>
    escapeHtml($_rating->getRatingCode())) ?>escapeHtml(__($_rating->getRatingCode())) ?>
    @@ -43,13 +43,13 @@
    -

    dateFormat($block->getReviewData()->getCreatedAt())) ?>

    +

    escapeHtml(__('Product Review (submitted on %1):', $block->dateFormat($block->getReviewData()->getCreatedAt()))) ?>

    escapeHtml($block->getReviewData()->getDetail())) ?>

    - + escapeHtml(__('Back to Product Reviews')) ?>
    diff --git a/app/code/Magento/Review/view/frontend/web/js/error-placement.js b/app/code/Magento/Review/view/frontend/web/js/error-placement.js index f05695778c4b8..6097c02d34764 100644 --- a/app/code/Magento/Review/view/frontend/web/js/error-placement.js +++ b/app/code/Magento/Review/view/frontend/web/js/error-placement.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Review/view/frontend/web/js/process-reviews.js b/app/code/Magento/Review/view/frontend/web/js/process-reviews.js index 124b59becf1cb..f28631986e10b 100644 --- a/app/code/Magento/Review/view/frontend/web/js/process-reviews.js +++ b/app/code/Magento/Review/view/frontend/web/js/process-reviews.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -11,7 +11,9 @@ define([ $.ajax({ url: url, cache: true, - dataType: 'html' + dataType: 'html', + showLoader: true, + loaderContext: $('.product.data.items') }).done(function (data) { $('#product-review-container').html(data); $('[data-role="product-review"] .pages a').each(function (index, element) { @@ -30,7 +32,17 @@ define([ } return function (config, element) { - processReviews(config.productReviewUrl); + var reviewTab = $(config.reviewsTabSelector); + var requiredReviewTabRole = 'tab'; + + if (reviewTab.attr('role') === requiredReviewTabRole && reviewTab.hasClass('active')) { + processReviews(config.productReviewUrl); + } else { + reviewTab.one('beforeOpen', function () { + processReviews(config.productReviewUrl); + }); + } + $(function () { $('.product-info-main .reviews-actions a').click(function (event) { event.preventDefault(); diff --git a/app/code/Magento/Review/view/frontend/web/js/view/review.js b/app/code/Magento/Review/view/frontend/web/js/view/review.js index 63689df7bec59..ffbae73fe6278 100644 --- a/app/code/Magento/Review/view/frontend/web/js/view/review.js +++ b/app/code/Magento/Review/view/frontend/web/js/view/review.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Rss/App/Action/Plugin/BackendAuthentication.php b/app/code/Magento/Rss/App/Action/Plugin/BackendAuthentication.php index 723b341597a2c..56c8b0e4282e3 100644 --- a/app/code/Magento/Rss/App/Action/Plugin/BackendAuthentication.php +++ b/app/code/Magento/Rss/App/Action/Plugin/BackendAuthentication.php @@ -2,7 +2,7 @@ /** * RSS Backend Authentication plugin * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Rss\App\Action\Plugin; diff --git a/app/code/Magento/Rss/Block/Feeds.php b/app/code/Magento/Rss/Block/Feeds.php index 5b902ffb14e61..1abdb1500f1f5 100644 --- a/app/code/Magento/Rss/Block/Feeds.php +++ b/app/code/Magento/Rss/Block/Feeds.php @@ -1,6 +1,6 @@ - */ class Rss { /** @@ -25,11 +22,22 @@ class Rss protected $cache; /** + * @var SerializerInterface + */ + private $serializer; + + /** + * Rss constructor + * * @param \Magento\Framework\App\CacheInterface $cache + * @param SerializerInterface|null $serializer */ - public function __construct(\Magento\Framework\App\CacheInterface $cache) - { + public function __construct( + \Magento\Framework\App\CacheInterface $cache, + SerializerInterface $serializer = null + ) { $this->cache = $cache; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -46,14 +54,14 @@ public function getFeeds() } if ($cache) { - return unserialize($cache); + return $this->serializer->unserialize($cache); } $data = $this->dataProvider->getRssData(); if ($this->dataProvider->getCacheKey() && $this->dataProvider->getCacheLifetime()) { $this->cache->save( - serialize($data), + $this->serializer->serialize($data), $this->dataProvider->getCacheKey(), ['rss'], $this->dataProvider->getCacheLifetime() diff --git a/app/code/Magento/Rss/Model/RssManager.php b/app/code/Magento/Rss/Model/RssManager.php index cfb4daa36e3d7..187349001c0cf 100644 --- a/app/code/Magento/Rss/Model/RssManager.php +++ b/app/code/Magento/Rss/Model/RssManager.php @@ -1,6 +1,6 @@ cacheInterface = $this->getMock(\Magento\Framework\App\CacheInterface::class); - + $this->cacheMock = $this->getMock(\Magento\Framework\App\CacheInterface::class); + $this->serializerMock = $this->getMock(SerializerInterface::class); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->rss = $this->objectManagerHelper->getObject( \Magento\Rss\Model\Rss::class, [ - 'cache' => $this->cacheInterface + 'cache' => $this->cacheMock, + 'serializer' => $this->serializerMock ] ); } @@ -64,8 +71,18 @@ public function testGetFeeds() $this->rss->setDataProvider($dataProvider); - $this->cacheInterface->expects($this->once())->method('load')->will($this->returnValue(false)); - $this->cacheInterface->expects($this->once())->method('save')->will($this->returnValue(true)); + $this->cacheMock->expects($this->once()) + ->method('load') + ->with('cache_key') + ->will($this->returnValue(false)); + $this->cacheMock->expects($this->once()) + ->method('save') + ->with('serializedData') + ->will($this->returnValue(true)); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($this->feedData) + ->willReturn('serializedData'); $this->assertEquals($this->feedData, $this->rss->getFeeds()); } @@ -79,9 +96,15 @@ public function testGetFeedsWithCache() $this->rss->setDataProvider($dataProvider); - $this->cacheInterface->expects($this->once())->method('load') - ->will($this->returnValue(serialize($this->feedData))); - $this->cacheInterface->expects($this->never())->method('save'); + $this->cacheMock->expects($this->once()) + ->method('load') + ->with('cache_key') + ->will($this->returnValue('serializedData')); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn($this->feedData); + $this->cacheMock->expects($this->never())->method('save'); $this->assertEquals($this->feedData, $this->rss->getFeeds()); } diff --git a/app/code/Magento/Rss/Test/Unit/Model/UrlBuilderTest.php b/app/code/Magento/Rss/Test/Unit/Model/UrlBuilderTest.php index 9bc950832f90d..6ab5e344b47b0 100644 --- a/app/code/Magento/Rss/Test/Unit/Model/UrlBuilderTest.php +++ b/app/code/Magento/Rss/Test/Unit/Model/UrlBuilderTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Rss/etc/adminhtml/di.xml b/app/code/Magento/Rss/etc/adminhtml/di.xml index d411833ae7767..8a43668affea6 100644 --- a/app/code/Magento/Rss/etc/adminhtml/di.xml +++ b/app/code/Magento/Rss/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/etc/adminhtml/routes.xml b/app/code/Magento/Rss/etc/adminhtml/routes.xml index 6219782d0b7b9..b76fd7221118a 100644 --- a/app/code/Magento/Rss/etc/adminhtml/routes.xml +++ b/app/code/Magento/Rss/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/etc/adminhtml/system.xml b/app/code/Magento/Rss/etc/adminhtml/system.xml index 0071d0fa19aed..d916bcd3e57ae 100644 --- a/app/code/Magento/Rss/etc/adminhtml/system.xml +++ b/app/code/Magento/Rss/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/etc/di.xml b/app/code/Magento/Rss/etc/di.xml index a2ab9f95f83cb..fbe92c28fdca5 100644 --- a/app/code/Magento/Rss/etc/di.xml +++ b/app/code/Magento/Rss/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/etc/frontend/page_types.xml b/app/code/Magento/Rss/etc/frontend/page_types.xml index 627f0ee0a9c64..d4d755a3d556d 100644 --- a/app/code/Magento/Rss/etc/frontend/page_types.xml +++ b/app/code/Magento/Rss/etc/frontend/page_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/etc/frontend/routes.xml b/app/code/Magento/Rss/etc/frontend/routes.xml index ed1d7907ecee9..8dd282271bed3 100644 --- a/app/code/Magento/Rss/etc/frontend/routes.xml +++ b/app/code/Magento/Rss/etc/frontend/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/etc/module.xml b/app/code/Magento/Rss/etc/module.xml index 8cc38f6ca6ef8..9aeb61e491a14 100644 --- a/app/code/Magento/Rss/etc/module.xml +++ b/app/code/Magento/Rss/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/registration.php b/app/code/Magento/Rss/registration.php index adce0c06f7dd8..5d557825c24f6 100644 --- a/app/code/Magento/Rss/registration.php +++ b/app/code/Magento/Rss/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Rss/view/frontend/layout/rss_index_index.xml b/app/code/Magento/Rss/view/frontend/layout/rss_index_index.xml index e95e250c9564e..eddf4a0581b40 100644 --- a/app/code/Magento/Rss/view/frontend/layout/rss_index_index.xml +++ b/app/code/Magento/Rss/view/frontend/layout/rss_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rss/view/frontend/templates/feeds.phtml b/app/code/Magento/Rss/view/frontend/templates/feeds.phtml index 7c7c3a48390ba..a491e00183f31 100644 --- a/app/code/Magento/Rss/view/frontend/templates/feeds.phtml +++ b/app/code/Magento/Rss/view/frontend/templates/feeds.phtml @@ -1,23 +1,24 @@ - - + - + getFeeds() as $feed): ?> @@ -26,7 +27,7 @@ diff --git a/app/code/Magento/Rule/Block/Actions.php b/app/code/Magento/Rule/Block/Actions.php index aea4ffbf034a8..348cb9f2d0018 100644 --- a/app/code/Magento/Rule/Block/Actions.php +++ b/app/code/Magento/Rule/Block/Actions.php @@ -1,6 +1,6 @@ _formFactory = $formFactory; $this->_localeDate = $localeDate; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\Serialize\Serializer\Json::class + ); parent::__construct( $context, $registry, - $this->getExtensionFactory(), - $this->getCustomAttributeFactory(), + $extensionFactory ?: $this->getExtensionFactory(), + $customAttributeFactory ?: $this->getCustomAttributeFactory(), $resource, $resourceCollection, $data @@ -126,13 +143,13 @@ public function beforeSave() // Serialize conditions if ($this->getConditions()) { - $this->setConditionsSerialized(serialize($this->getConditions()->asArray())); + $this->setConditionsSerialized($this->serializer->serialize($this->getConditions()->asArray())); $this->_conditions = null; } // Serialize actions if ($this->getActions()) { - $this->setActionsSerialized(serialize($this->getActions()->asArray())); + $this->setActionsSerialized($this->serializer->serialize($this->getActions()->asArray())); $this->_actions = null; } @@ -189,7 +206,7 @@ public function getConditions() if ($this->hasConditionsSerialized()) { $conditions = $this->getConditionsSerialized(); if (!empty($conditions)) { - $conditions = unserialize($conditions); + $conditions = $this->serializer->unserialize($conditions); if (is_array($conditions) && !empty($conditions)) { $this->_conditions->loadArray($conditions); } @@ -227,7 +244,7 @@ public function getActions() if ($this->hasActionsSerialized()) { $actions = $this->getActionsSerialized(); if (!empty($actions)) { - $actions = unserialize($actions); + $actions = $this->serializer->unserialize($actions); if (is_array($actions) && !empty($actions)) { $this->_actions->loadArray($actions); } diff --git a/app/code/Magento/Rule/Model/Action/AbstractAction.php b/app/code/Magento/Rule/Model/Action/AbstractAction.php index 3be6ba0ee26b2..4c9ff71c63627 100644 --- a/app/code/Magento/Rule/Model/Action/AbstractAction.php +++ b/app/code/Magento/Rule/Model/Action/AbstractAction.php @@ -1,6 +1,6 @@ isAttributeSetOrCategory()) { + if ($this->getAttribute() == 'sku') { + $mappedSqlField = 'e.sku'; + } elseif (!$this->isAttributeSetOrCategory()) { $mappedSqlField = $this->getEavAttributeTableAlias() . '.value'; } elseif ($this->getAttribute() == 'category_ids') { $mappedSqlField = 'e.entity_id'; diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index f427dfc39504f..2e500cd777071 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -1,6 +1,6 @@ _getAssociatedEntityInfo('website'); if (!$this->getFlag('is_website_table_joined')) { + $websiteIds = is_array($websiteId) ? $websiteId : [$websiteId]; + $entityInfo = $this->_getAssociatedEntityInfo('website'); $this->setFlag('is_website_table_joined', true); - if ($websiteId instanceof \Magento\Store\Model\Website) { - $websiteId = $websiteId->getId(); + foreach ($websiteIds as $index => $website) { + if ($website instanceof \Magento\Store\Model\Website) { + $websiteIds[$index] = $website->getId(); + } } $this->getSelect()->join( ['website' => $this->getTable($entityInfo['associations_table'])], - $this->getConnection()->quoteInto('website.' . $entityInfo['entity_id_field'] . ' = ?', $websiteId) + $this->getConnection()->quoteInto('website.' . $entityInfo['entity_id_field'] . ' IN (?)', $websiteIds) . ' AND main_table.' . $entityInfo['rule_id_field'] . ' = website.' . $entityInfo['rule_id_field'], [] ); diff --git a/app/code/Magento/Rule/Test/Unit/Model/AbstractModelTest.php b/app/code/Magento/Rule/Test/Unit/Model/AbstractModelTest.php new file mode 100644 index 0000000000000..652b92fd2491a --- /dev/null +++ b/app/code/Magento/Rule/Test/Unit/Model/AbstractModelTest.php @@ -0,0 +1,209 @@ +localeDateMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->formFactoryMock = $this->getMockBuilder(\Magento\Framework\Data\FormFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->registryMock = $this->getMockBuilder(\Magento\Framework\Registry::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->contextMock = $this->getMockBuilder(\Magento\Framework\Model\Context::class) + ->disableOriginalConstructor() + ->setMethods(['getEventDispatcher']) + ->getMock(); + + $this->eventManagerMock = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['dispatch']) + ->getMock(); + $this->contextMock->expects($this->any()) + ->method('getEventDispatcher') + ->will($this->returnValue($this->eventManagerMock)); + + $resourceMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\AbstractResource::class) + ->disableOriginalConstructor() + ->getMock(); + $resourceCollectionMock = $this->getMockBuilder(\Magento\Framework\Data\Collection\AbstractDb::class) + ->disableOriginalConstructor() + ->getMock(); + $extensionFactory = $this->getMockBuilder(\Magento\Framework\Api\ExtensionAttributesFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $customAttributeFactory = $this->getMockBuilder(\Magento\Framework\Api\AttributeValueFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = $this->getMockForAbstractClass( + \Magento\Rule\Model\AbstractModel::class, + [ + 'context' => $this->contextMock, + 'registry' => $this->registryMock, + 'formFactory' => $this->formFactoryMock, + 'localeDate' => $this->localeDateMock, + 'resource' => $resourceMock, + 'resourceCollection' => $resourceCollectionMock, + 'data' => [], + 'extensionFactory' => $extensionFactory, + 'customAttributeFactory' => $customAttributeFactory, + 'serializer' => $this->getSerializerMock(), + ] + ); + } + + /** + * Get mock for serializer + * + * @return \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject + */ + private function getSerializerMock() + { + $serializerMock = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->setMethods(['serialize', 'unserialize']) + ->getMock(); + + $serializerMock->expects($this->any()) + ->method('serialize') + ->will( + $this->returnCallback( + function ($value) { + return json_encode($value); + } + ) + ); + + $serializerMock->expects($this->any()) + ->method('unserialize') + ->will( + $this->returnCallback( + function ($value) { + return json_decode($value, true); + } + ) + ); + + return $serializerMock; + } + + public function testGetConditions() + { + $conditionsArray = ['conditions' => 'serialized']; + $serializedConditions = json_encode($conditionsArray); + $conditions = $this->getMockBuilder(\Magento\Rule\Model\Condition\Combine::class) + ->setMethods(['setRule', 'setId', 'setPrefix', 'loadArray']) + ->disableOriginalConstructor() + ->getMock(); + + $conditions->expects($this->once())->method('setRule')->will($this->returnSelf()); + $conditions->expects($this->once())->method('setId')->will($this->returnSelf()); + $conditions->expects($this->once())->method('setPrefix')->will($this->returnSelf()); + + $this->model->expects($this->once())->method('getConditionsInstance')->will($this->returnValue($conditions)); + + $this->model->setConditionsSerialized($serializedConditions); + + $conditions->expects($this->once())->method('loadArray')->with($conditionsArray); + + $this->assertEquals($conditions, $this->model->getConditions()); + } + + public function testGetActions() + { + $actionsArray = ['actions' => 'some_actions']; + $actionsSerialized = json_encode($actionsArray); + $actions = $this->getMockBuilder(\Magento\Rule\Model\Action\Collection::class) + ->setMethods(['setRule', 'setId', 'setPrefix', 'loadArray']) + ->disableOriginalConstructor() + ->getMock(); + + $actions->expects($this->once())->method('setRule')->will($this->returnSelf()); + $actions->expects($this->once())->method('setId')->will($this->returnSelf()); + $actions->expects($this->once())->method('setPrefix')->will($this->returnSelf()); + + $this->model->expects($this->once())->method('getActionsInstance')->will($this->returnValue($actions)); + + $this->model->setActionsSerialized($actionsSerialized); + + $actions->expects($this->once())->method('loadArray')->with($actionsArray); + + $this->assertEquals($actions, $this->model->getActions()); + } + + public function testBeforeSave() + { + $conditions = $this->getMockBuilder(\Magento\Rule\Model\Condition\Combine::class) + ->setMethods(['asArray']) + ->disableOriginalConstructor() + ->getMock(); + + $actions = $this->getMockBuilder(\Magento\Rule\Model\Action\Collection::class) + ->setMethods(['asArray']) + ->disableOriginalConstructor() + ->getMock(); + + $this->model->setConditions($conditions); + $this->model->setActions($actions); + + $conditions->expects($this->any())->method('asArray')->will($this->returnValue(['conditions' => 'array'])); + $actions->expects($this->any())->method('asArray')->will($this->returnValue(['actions' => 'array'])); + + $this->eventManagerMock->expects($this->exactly(2))->method('dispatch'); + + $this->assertEquals($this->model, $this->model->beforeSave()); + $this->assertEquals(json_encode(['conditions' => 'array']), $this->model->getConditionsSerialized()); + $this->assertEquals(json_encode(['actions' => 'array']), $this->model->getActionsSerialized()); + } +} diff --git a/app/code/Magento/Rule/Test/Unit/Model/ActionFactoryTest.php b/app/code/Magento/Rule/Test/Unit/Model/ActionFactoryTest.php index 0a9fe3f7d5936..a2a34f084c1f9 100644 --- a/app/code/Magento/Rule/Test/Unit/Model/ActionFactoryTest.php +++ b/app/code/Magento/Rule/Test/Unit/Model/ActionFactoryTest.php @@ -1,6 +1,6 @@ _entityFactoryMock = $this->getMock(\Magento\Framework\Data\Collection\EntityFactoryInterface::class); @@ -152,6 +162,30 @@ public function testAddWebsiteFilter() ); } + public function testAddWebsiteFilterArray() + { + $this->selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->connectionMock->expects($this->atLeastOnce()) + ->method('quoteInto') + ->with($this->equalTo('website. IN (?)'), $this->equalTo(['2', '3'])) + ->willReturn(true); + + $this->abstractCollection->expects($this->atLeastOnce())->method('getSelect')->willReturn($this->selectMock); + $this->abstractCollection->expects($this->atLeastOnce())->method('getConnection') + ->willReturn($this->connectionMock); + + $this->assertInstanceOf( + \Magento\Rule\Model\ResourceModel\Rule\Collection\AbstractCollection::class, + $this->abstractCollection->addWebsiteFilter(['2', '3']) + ); + } + public function testAddFieldToFilter() { $this->_prepareAddFilterStubs(); diff --git a/app/code/Magento/Rule/composer.json b/app/code/Magento/Rule/composer.json index 95b8e6ffec2a6..31ee3254d99b9 100644 --- a/app/code/Magento/Rule/composer.json +++ b/app/code/Magento/Rule/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-rule", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/module-store": "100.2.*", "magento/module-eav": "100.2.*", "magento/module-catalog": "101.1.*", diff --git a/app/code/Magento/Rule/etc/module.xml b/app/code/Magento/Rule/etc/module.xml index 852de7d387d41..0bcb9be6679c9 100644 --- a/app/code/Magento/Rule/etc/module.xml +++ b/app/code/Magento/Rule/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Rule/registration.php b/app/code/Magento/Rule/registration.php index 0cfbb2b866077..d72d4fd9b6132 100644 --- a/app/code/Magento/Rule/registration.php +++ b/app/code/Magento/Rule/registration.php @@ -1,6 +1,6 @@ getPriceInfo()->getPrice(FinalPrice::PRICE_CODE)->getValue(); + return $this->convertPrice($price); + } + /** * Convert price * - * @param float $value + * @param int|float $value * @param bool $format - * @return float + * @return string|int|float */ public function convertPrice($value, $format = true) { diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Address.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Address.php index f073f042cba5a..555f13a9a57df 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Address.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Address.php @@ -1,6 +1,6 @@ _sessionQuote = $sessionQuote; - parent::__construct($context, $paymentHelper, $methodSpecificationFactory, $data); + parent::__construct($context, $paymentHelper, $methodSpecificationFactory, $data, $additionalChecks); } /** diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Comment.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Comment.php index c6923555eab18..b4cb2ecbe3463 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Comment.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Comment.php @@ -1,6 +1,6 @@ getOptions() as $optionData) { - $options[] = ConvertArray::toFlatArray( - $this->dataObjectProcessor->buildOutputDataArray( - $optionData, - \Magento\Customer\Api\Data\OptionInterface::class - ) + $data = $this->dataObjectProcessor->buildOutputDataArray( + $optionData, + \Magento\Customer\Api\Data\OptionInterface::class ); + foreach ($data as $key => $value) { + if (is_array($value)) { + unset($data[$key]); + $data['value'] = $value; + } + } + $options[] = $data; } $element->setValues($options); } elseif ($inputType == 'date') { diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php index 59d4fb4708d29..6a20d9a2aff1f 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Account.php @@ -1,6 +1,6 @@ directoryHelper->getDefaultCountry($this->getStore()) ); } - + $this->processCountryOptions($this->_form->getElement('country_id')); // Set custom renderer for VAT field if needed $vatIdElement = $this->_form->getElement('vat_id'); if ($vatIdElement && $this->getDisplayVatValidationButton() !== false) { @@ -279,6 +291,49 @@ protected function _prepareForm() return $this; } + /** + * @param \Magento\Framework\Data\Form\Element\AbstractElement $countryElement + * @return void + */ + private function processCountryOptions(\Magento\Framework\Data\Form\Element\AbstractElement $countryElement) + { + $storeId = $this->getBackendQuoteSession()->getStoreId(); + $options = $this->getCountriesCollection() + ->loadByStore($storeId) + ->toOptionArray(); + + $countryElement->setValues($options); + } + + /** + * Retrieve Directiry Countries collection + * @deprecated + * @return \Magento\Directory\Model\ResourceModel\Country\Collection + */ + private function getCountriesCollection() + { + if (!$this->countriesCollection) { + $this->countriesCollection = ObjectManager::getInstance() + ->get(\Magento\Directory\Model\ResourceModel\Country\Collection::class); + } + + return $this->countriesCollection; + } + + /** + * Retrieve Backend Quote Session + * @deprecated + * @return Quote + */ + private function getBackendQuoteSession() + { + if (!$this->backendQuoteSession) { + $this->backendQuoteSession = ObjectManager::getInstance()->get(Quote::class); + } + + return $this->backendQuoteSession; + } + /** * Add additional data to form element * diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Giftmessage.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Giftmessage.php index 96d7d599809d8..9cbc0e1761f51 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Giftmessage.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Giftmessage.php @@ -1,6 +1,6 @@ _localeDate->formatDateTime($date, $format, $format); + return $this->formatDate($item['created_at'], $format); } - return $this->_localeDate->formatDateTime($date, \IntlDateFormatter::NONE, $format); + return $this->formatTime($item['created_at'], $format); } /** diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/Info.php b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/Info.php index dba0c8517d022..44ad46cbf8ab0 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/Info.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/View/Tab/Info.php @@ -1,6 +1,6 @@ setOrderIncrementIdHtml($this->escapeHtml($this->_txn->getOrder()->getIncrementId())); - $this->setTxnTypeHtml($this->escapeHtml($this->_txn->getTxnType())); + $this->setTxnTypeHtml($this->escapeHtml(__($this->_txn->getTxnType()))); $this->setOrderIdUrlHtml( $this->escapeHtml($this->getUrl('sales/order/view', ['order_id' => $this->_txn->getOrderId()])) diff --git a/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail/Grid.php b/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail/Grid.php index 136376e254604..b7ad6c69efd97 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail/Grid.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail/Grid.php @@ -1,6 +1,6 @@ getStatus(); if ($value) { - $cell = $value . '[' . $this->_config->getStateLabel($value) . ']'; + $cell = $value . '[' . $this->_config->getStateLabelByStateAndStatus($value, $status) . ']'; } else { $cell = $value; } diff --git a/app/code/Magento/Sales/Block/Status/Grid/Column/Unassign.php b/app/code/Magento/Sales/Block/Status/Grid/Column/Unassign.php index e2e3741964d9d..1286b45e90be1 100644 --- a/app/code/Magento/Sales/Block/Status/Grid/Column/Unassign.php +++ b/app/code/Magento/Sales/Block/Status/Grid/Column/Unassign.php @@ -1,6 +1,6 @@ _objectManager->create( \Magento\Sales\Api\CreditmemoManagementInterface::class ); + $creditmemo->getOrder()->setCustomerNoteNotify(!empty($data['send_email'])); $creditmemoManagement->refund($creditmemo, (bool)$data['do_offline']); if (!empty($data['send_email'])) { diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Start.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Start.php index ad6588188209e..9d2c846657b62 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Start.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Start.php @@ -1,6 +1,6 @@ getAllItems() as $creditmemoItem) { $orderItem = $creditmemoItem->getOrderItem(); $parentId = $orderItem->getParentItemId(); - if (isset($backToStock[$orderItem->getId()])) { + if ($parentId && isset($backToStock[$parentId]) && $backToStock[$parentId]) { $creditmemoItem->setBackToStock(true); - } elseif ($orderItem->getParentItem() && isset($backToStock[$parentId]) && $backToStock[$parentId]) { + } elseif (isset($backToStock[$orderItem->getId()])) { $creditmemoItem->setBackToStock(true); } elseif (empty($savedData)) { $creditmemoItem->setBackToStock( diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemos.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemos.php index bdd21d7891c27..d67a8f8e913a9 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemos.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemos.php @@ -1,6 +1,6 @@ filter->getCollection($this->getOrderCollection()->create()); + return $this->massAction($collection); + } catch (\Exception $e) { + $this->messageManager->addError($e->getMessage()); + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + return $resultRedirect->setPath($this->redirectUrl); + } + } + + /** + * Get Order Collection Factory + * + * @return \Magento\Sales\Model\ResourceModel\Order\CollectionFactory + * @deprecated + */ + private function getOrderCollection() + { + if ($this->orderCollectionFactory === null) { + $this->orderCollectionFactory = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class + ); + } + return $this->orderCollectionFactory; + } +} diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php index 119333e85f325..15400266a193c 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfcreditmemos.php @@ -1,6 +1,6 @@ resultRedirectFactory->create()->setPath($this->getComponentRefererUrl()); } return $this->fileFactory->create( - sprintf('packingslip%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), + sprintf('invoice%s.pdf', $this->dateTime->date('Y-m-d_H-i-s')), $this->pdfInvoice->getPdf($invoicesCollection->getItems())->render(), DirectoryList::VAR_DIR, 'application/pdf' diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php index e538746997c77..3858ab83763ce 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Pdfshipments.php @@ -1,6 +1,6 @@ resultForwardFactory = $resultForwardFactory; $this->download = $download; $this->unserialize = $unserialize; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get( + \Magento\Framework\Serialize\Serializer\Json::class + ); } /** @@ -88,7 +103,7 @@ public function execute() } try { - $info = $this->unserialize->unserialize($option->getValue()); + $info = $this->serializer->unserialize($option->getValue()); if ($this->getRequest()->getParam('key') != $info['secret_key']) { return $resultForward->forward('noroute'); } diff --git a/app/code/Magento/Sales/Controller/Guest/Creditmemo.php b/app/code/Magento/Sales/Controller/Guest/Creditmemo.php index 8015b5bc7641d..76c6e979f70fc 100644 --- a/app/code/Magento/Sales/Controller/Guest/Creditmemo.php +++ b/app/code/Magento/Sales/Controller/Guest/Creditmemo.php @@ -1,7 +1,7 @@ _objectManager = $objectManager; $this->_eventManager = $eventManager; @@ -312,6 +321,8 @@ public function __construct( $this->dataObjectHelper = $dataObjectHelper; $this->orderManagement = $orderManagement; $this->quoteFactory = $quoteFactory; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($data); } @@ -632,7 +643,7 @@ public function initFromOrderItem(\Magento\Sales\Model\Order\Item $orderItem, $q [ 'product' => $item->getProduct(), 'code' => 'additional_options', - 'value' => serialize($additionalOptions) + 'value' => $this->serializer->serialize($additionalOptions) ] ) ); @@ -794,7 +805,9 @@ public function moveQuoteItem($item, $moveTo, $qty) $info = $item->getOptionByCode('info_buyRequest'); if ($info) { - $info = new \Magento\Framework\DataObject(unserialize($info->getValue())); + $info = new \Magento\Framework\DataObject( + $this->serializer->unserialize($info->getValue()) + ); $info->setQty($qty); $info->setOptions($this->_prepareOptionsForRequest($item)); } else { @@ -1102,6 +1115,8 @@ public function updateQuoteItems($items) * @param string $additionalOptions * @return array * @throws \Magento\Framework\Exception\LocalizedException + * + * @deprecated */ protected function _parseOptions(\Magento\Quote\Model\Quote\Item $item, $additionalOptions) { @@ -1166,6 +1181,8 @@ protected function _parseOptions(\Magento\Quote\Model\Quote\Item $item, $additio * @param \Magento\Quote\Model\Quote\Item $item * @param array $options * @return $this + * + * @deprecated */ protected function _assignOptionsToItem(\Magento\Quote\Model\Quote\Item $item, $options) { @@ -1209,7 +1226,7 @@ protected function _assignOptionsToItem(\Magento\Quote\Model\Quote\Item $item, $ [ 'product' => $item->getProduct(), 'code' => 'additional_options', - 'value' => serialize($options['additional_options']) + 'value' => $this->serializer->serialize($options['additional_options']) ] ) ); @@ -1287,7 +1304,7 @@ protected function _createCustomerForm(\Magento\Customer\Api\Data\CustomerInterf 'adminhtml_checkout', $this->customerMapper->toFlatArray($customer), false, - CustomerForm::DONT_IGNORE_INVISIBLE + CustomerForm::IGNORE_INVISIBLE ); return $customerForm; @@ -1547,6 +1564,11 @@ public function setPaymentData($data) public function applyCoupon($code) { $code = trim((string)$code); + $this->getQuote()->getShippingAddress()->setCollectShippingRates(true); + + if (empty($code)) { + $this->getQuote()->getShippingAddress()->setFreeShipping(null); + } $this->getQuote()->setCouponCode($code); $this->setRecollect(true); @@ -1563,13 +1585,11 @@ public function setAccountData($accountData) { $customer = $this->getQuote()->getCustomer(); $form = $this->_createCustomerForm($customer); - $customerData = $this->customerMapper->toFlatArray($customer); // emulate request $request = $form->prepareRequest($accountData); $data = $form->extractData($request); $data = $form->restoreData($data); - $data = array_merge($customerData, array_filter($data)); $customer = $this->customerFactory->create(); $this->dataObjectHelper->populateWithArray( $customer, @@ -1578,6 +1598,7 @@ public function setAccountData($accountData) $this->getQuote()->updateCustomerData($customer); $data = []; + $customerData = $this->customerMapper->toFlatArray($customer); foreach ($form->getAttributes() as $attribute) { $code = sprintf('customer_%s', $attribute->getAttributeCode()); $data[$code] = isset($customerData[$attribute->getAttributeCode()]) @@ -1840,7 +1861,7 @@ protected function _prepareQuoteItems() } $addOptions = $item->getOptionByCode('additional_options'); if ($addOptions) { - $options['additional_options'] = unserialize($addOptions->getValue()); + $options['additional_options'] = $this->serializer->unserialize($addOptions->getValue()); } $item->setProductOrderOptions($options); } diff --git a/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php b/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php index efc6595bb2d51..bcb3dce328239 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php +++ b/app/code/Magento/Sales/Model/AdminOrder/EmailSender.php @@ -1,6 +1,6 @@ _configCacheType = $configCacheType; $this->_logger = $logger; $this->_salesConfig = $salesConfig; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -179,11 +190,11 @@ protected function _initCollectors() $sortedCodes = []; $cachedData = $this->_configCacheType->load($this->_collectorsCacheKey); if ($cachedData) { - $sortedCodes = unserialize($cachedData); + $sortedCodes = $this->serializer->unserialize($cachedData); } if (!$sortedCodes) { $sortedCodes = $this->_getSortedCollectorCodes($this->_modelsConfig); - $this->_configCacheType->save(serialize($sortedCodes), $this->_collectorsCacheKey); + $this->_configCacheType->save($this->serializer->serialize($sortedCodes), $this->_collectorsCacheKey); } foreach ($sortedCodes as $code) { $this->_collectors[$code] = $this->_models[$code]; diff --git a/app/code/Magento/Sales/Model/Config/Reader.php b/app/code/Magento/Sales/Model/Config/Reader.php index 8843efd5140ef..c9ec4b653f6aa 100644 --- a/app/code/Magento/Sales/Model/Config/Reader.php +++ b/app/code/Magento/Sales/Model/Config/Reader.php @@ -1,6 +1,6 @@ resourceConnection = $resourceConnection; $this->orderRepository = $orderRepository; $this->invoiceDocumentFactory = $invoiceDocumentFactory; - $this->invoiceValidator = $invoiceValidator; - $this->orderValidator = $orderValidator; $this->paymentAdapter = $paymentAdapter; $this->orderStateResolver = $orderStateResolver; $this->config = $config; $this->invoiceRepository = $invoiceRepository; + $this->invoiceOrderValidator = $invoiceOrderValidator; $this->notifierInterface = $notifierInterface; $this->logger = $logger; } @@ -158,19 +147,19 @@ public function execute( ($appendComment && $notify), $arguments ); - $errorMessages = array_merge( - $this->invoiceValidator->validate( - $invoice, - [InvoiceQuantityValidator::class] - ), - $this->orderValidator->validate( - $order, - [CanInvoice::class] - ) + $errorMessages = $this->invoiceOrderValidator->validate( + $order, + $invoice, + $capture, + $items, + $notify, + $appendComment, + $comment, + $arguments ); - if (!empty($errorMessages)) { + if ($errorMessages->hasMessages()) { throw new \Magento\Sales\Exception\DocumentValidationException( - __("Invoice Document Validation Error(s):\n" . implode("\n", $errorMessages)) + __("Invoice Document Validation Error(s):\n" . implode("\n", $errorMessages->getMessages())) ); } $connection->beginTransaction(); diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index b42c573d9435b..1d9849064f204 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -1,6 +1,6 @@ addressConfig->setStore($address->getOrder()->getStoreId()); $formatType = $this->addressConfig->getFormatByCode($type); if (!$formatType || !$formatType->getRenderer()) { return null; diff --git a/app/code/Magento/Sales/Model/Order/Address/Validator.php b/app/code/Magento/Sales/Model/Order/Address/Validator.php index 8072188337880..f46d8c4979a1c 100644 --- a/app/code/Magento/Sales/Model/Order/Address/Validator.php +++ b/app/code/Magento/Sales/Model/Order/Address/Validator.php @@ -1,6 +1,6 @@ stateStatuses[$key])) { return $this->stateStatuses[$key]; } @@ -256,4 +256,22 @@ protected function _getStatuses($visibility) } return $this->statuses[(bool) $visibility]; } + + /** + * Retrieve label by state and status + * + * @param string $state + * @param string $status + * @return \Magento\Framework\Phrase|string + */ + public function getStateLabelByStateAndStatus($state, $status) + { + foreach ($this->_getCollection() as $item) { + if ($item->getData('state') == $state && $item->getData('status') == $status) { + $label = $item->getData('label'); + return __($label); + } + } + return $state; + } } diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index 02b2826f14f6e..743cf53b5b528 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -1,6 +1,6 @@ getAllItems() as $item) { + $items = $this->getAllItems(); + foreach ($items as $item) { if (!$item->isLast()) { return false; } } + + if (empty($items)) { + $order = $this->getOrder(); + if ($order) { + foreach ($order->getItems() as $orderItem) { + if ($orderItem->canRefund()) { + return false; + } + } + } + } + return true; } diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php index 31532d5881dfd..a3b6d0fbd5e83 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php @@ -1,6 +1,6 @@ extensionAttributes; + } + + /** + * Set an extension attributes object. + * + * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\Sales\Api\Data\CreditmemoCommentCreationExtensionInterface $extensionAttributes + ) { + $this->extensionAttributes = $extensionAttributes; + return $this; + } + + /** + * @inheritdoc + */ + public function getComment() + { + return $this->comment; + } + + /** + * @inheritdoc + */ + public function setComment($comment) + { + $this->comment = $comment; + return $this; + } + + /** + * @inheritdoc + */ + public function getIsVisibleOnFront() + { + return $this->isVisibleOnFront; + } + + /** + * @inheritdoc + */ + public function setIsVisibleOnFront($isVisibleOnFront) + { + $this->isVisibleOnFront = $isVisibleOnFront; + return $this; + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Config.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Config.php index f2d93b262d8aa..a18305191340e 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Config.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Config.php @@ -2,7 +2,7 @@ /** * Order creditmemo configuration model * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Sales\Model\Order\Creditmemo; diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CreationArguments.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CreationArguments.php new file mode 100644 index 0000000000000..5964afeef4551 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CreationArguments.php @@ -0,0 +1,104 @@ +shippingAmount; + } + + /** + * @inheritdoc + */ + public function getAdjustmentPositive() + { + return $this->adjustmentPositive; + } + + /** + * @inheritdoc + */ + public function getAdjustmentNegative() + { + return $this->adjustmentNegative; + } + + /** + * @inheritdoc + */ + public function setShippingAmount($amount) + { + $this->shippingAmount = $amount; + return $this; + } + + /** + * @inheritdoc + */ + public function setAdjustmentPositive($amount) + { + $this->adjustmentPositive = $amount; + return $this; + } + + /** + * @inheritdoc + */ + public function setAdjustmentNegative($amount) + { + $this->adjustmentNegative = $amount; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getExtensionAttributes() + { + return $this->extensionAttributes; + } + + /** + * {@inheritdoc} + */ + public function setExtensionAttributes( + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsExtensionInterface $extensionAttributes + ) { + $this->extensionAttributes = $extensionAttributes; + + return $this; + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidator.php new file mode 100644 index 0000000000000..b27afb510d139 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidator.php @@ -0,0 +1,36 @@ +validator = $validator; + } + + /** + * @inheritdoc + */ + public function validate(CreditmemoInterface $entity, array $validators) + { + return $this->validator->validate($entity, $validators); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php new file mode 100644 index 0000000000000..ad0862607170b --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/CreditmemoValidatorInterface.php @@ -0,0 +1,25 @@ +orderItemRepository = $orderItemRepository; + $this->context = $context; + } + + /** + * @inheritdoc + */ + public function validate($entity) + { + try { + $orderItem = $this->orderItemRepository->get($entity->getOrderItemId()); + if (!$this->isItemPartOfContextOrder($orderItem)) { + return [__('The creditmemo contains product item that is not part of the original order.')]; + } + } catch (NoSuchEntityException $e) { + return [__('The creditmemo contains product item that is not part of the original order.')]; + } + + if (!$this->isQtyAvailable($orderItem, $entity->getQty())) { + return [__('The quantity to refund must not be greater than the unrefunded quantity.')]; + } + + return []; + } + + /** + * @param Item $orderItem + * @param int $qty + * @return bool + */ + private function isQtyAvailable(Item $orderItem, $qty) + { + return $qty <= $orderItem->getQtyToRefund() || $orderItem->isDummy(); + } + + /** + * @param OrderItemInterface $orderItem + * @return bool + */ + private function isItemPartOfContextOrder(OrderItemInterface $orderItem) + { + return $this->context instanceof OrderInterface && $this->context->getEntityId() === $orderItem->getOrderId(); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreation.php b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreation.php new file mode 100644 index 0000000000000..16699ecc52ce9 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreation.php @@ -0,0 +1,86 @@ +orderItemId; + } + + /** + * {@inheritdoc} + */ + public function setOrderItemId($orderItemId) + { + $this->orderItemId = $orderItemId; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getQty() + { + return $this->qty; + } + + /** + * {@inheritdoc} + */ + public function setQty($qty) + { + $this->qty = $qty; + return $this; + } + + /** + * Retrieve existing extension attributes object or create a new one. + * + * @return \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface|null + */ + public function getExtensionAttributes() + { + return $this->extensionAttributes; + } + + /** + * Set an extension attributes object. + * + * @param \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\Sales\Api\Data\CreditmemoItemCreationExtensionInterface $extensionAttributes + ) { + $this->extensionAttributes = $extensionAttributes; + return $this; + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidator.php new file mode 100644 index 0000000000000..283cc4bbff6d3 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidator.php @@ -0,0 +1,40 @@ +validator = $validator; + } + + /** + * @inheritdoc + */ + public function validate( + CreditmemoItemCreationInterface $entity, + array $validators, + OrderInterface $context = null + ) { + return $this->validator->validate($entity, $validators, $context); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php new file mode 100644 index 0000000000000..1e822d7557d2f --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/ItemCreationValidatorInterface.php @@ -0,0 +1,24 @@ +senders = $senders; + } + + /** + * {@inheritdoc} + */ + public function notify( + \Magento\Sales\Api\Data\OrderInterface $order, + \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo, + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + $forceSyncMode = false + ) { + foreach ($this->senders as $sender) { + $sender->send($order, $creditmemo, $comment, $forceSyncMode); + } + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/NotifierInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/NotifierInterface.php new file mode 100644 index 0000000000000..8b4e07e1902e8 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/NotifierInterface.php @@ -0,0 +1,31 @@ +getBaseTotalInvoicedCost() - $creditmemo->getBaseCost() ); - if ($online) { - $order->getPayment()->refund($creditmemo); - } + $creditmemo->setDoTransaction($online); + $order->getPayment()->refund($creditmemo); $this->eventManager->dispatch('sales_order_creditmemo_refund', ['creditmemo' => $creditmemo]); } diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php new file mode 100644 index 0000000000000..c51000695fe20 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php @@ -0,0 +1,149 @@ +paymentHelper = $paymentHelper; + $this->creditmemoResource = $creditmemoResource; + $this->globalConfig = $globalConfig; + $this->eventManager = $eventManager; + } + + /** + * Sends order creditmemo email to the customer. + * + * Email will be sent immediately in two cases: + * + * - if asynchronous email sending is disabled in global settings + * - if $forceSyncMode parameter is set to TRUE + * + * Otherwise, email will be sent later during running of + * corresponding cron job. + * + * @param \Magento\Sales\Api\Data\OrderInterface $order + * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo + * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment + * @param bool $forceSyncMode + * + * @return bool + */ + public function send( + \Magento\Sales\Api\Data\OrderInterface $order, + \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo, + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + $forceSyncMode = false + ) { + $creditmemo->setSendEmail(true); + + if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) { + $transport = [ + 'order' => $order, + 'creditmemo' => $creditmemo, + 'comment' => $comment ? $comment->getComment() : '', + 'billing' => $order->getBillingAddress(), + 'payment_html' => $this->getPaymentHtml($order), + 'store' => $order->getStore(), + 'formattedShippingAddress' => $this->getFormattedShippingAddress($order), + 'formattedBillingAddress' => $this->getFormattedBillingAddress($order), + ]; + + $this->eventManager->dispatch( + 'email_creditmemo_set_template_vars_before', + ['sender' => $this, 'transport' => $transport] + ); + + $this->templateContainer->setTemplateVars($transport); + + if ($this->checkAndSend($order)) { + $creditmemo->setEmailSent(true); + + $this->creditmemoResource->saveAttribute($creditmemo, ['send_email', 'email_sent']); + + return true; + } + } else { + $creditmemo->setEmailSent(null); + + $this->creditmemoResource->saveAttribute($creditmemo, 'email_sent'); + } + + $this->creditmemoResource->saveAttribute($creditmemo, 'send_email'); + + return false; + } + + /** + * Returns payment info block as HTML. + * + * @param \Magento\Sales\Api\Data\OrderInterface $order + * + * @return string + */ + private function getPaymentHtml(\Magento\Sales\Api\Data\OrderInterface $order) + { + return $this->paymentHelper->getInfoBlockHtml( + $order->getPayment(), + $this->identityContainer->getStore()->getStoreId() + ); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/SenderInterface.php b/app/code/Magento/Sales/Model/Order/Creditmemo/SenderInterface.php new file mode 100644 index 0000000000000..9d3661f90ca42 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/SenderInterface.php @@ -0,0 +1,29 @@ +orderRepository = $orderRepository; + $this->invoiceRepository = $invoiceRepository; + $this->priceCurrency = $priceCurrency; + } + + /** + * @inheritdoc + */ + public function validate($entity) + { + /** + * @var $entity CreditmemoInterface + */ + if ($entity->getOrderId() === null) { + return [__('Order Id is required for creditmemo document')]; + } + + $messages = []; + + $order = $this->orderRepository->get($entity->getOrderId()); + $orderItemsById = $this->getOrderItems($order); + $invoiceQtysRefundLimits = $this->getInvoiceQtysRefundLimits($entity, $order); + + $totalQuantity = 0; + foreach ($entity->getItems() as $item) { + if (!isset($orderItemsById[$item->getOrderItemId()])) { + $messages[] = __( + 'The creditmemo contains product SKU "%1" that is not part of the original order.', + $item->getSku() + ); + continue; + } + $orderItem = $orderItemsById[$item->getOrderItemId()]; + + if ( + !$this->canRefundItem($orderItem, $item->getQty(), $invoiceQtysRefundLimits) || + !$this->isQtyAvailable($orderItem, $item->getQty()) + ) { + $messages[] =__( + 'The quantity to creditmemo must not be greater than the unrefunded quantity' + . ' for product SKU "%1".', + $orderItem->getSku() + ); + } else { + $totalQuantity += $item->getQty(); + } + } + + if ($entity->getGrandTotal() <= 0) { + $messages[] = __('The credit memo\'s total must be positive.'); + } elseif ($totalQuantity <= 0 && !$this->canRefundShipping($order)) { + $messages[] = __('You can\'t create a creditmemo without products.'); + } + + return $messages; + } + + /** + * We can have problem with float in php (on some server $a=762.73;$b=762.73; $a-$b!=0) + * for this we have additional diapason for 0 + * TotalPaid - contains amount, that were not rounded. + * + * @param OrderInterface $order + * @return bool + */ + private function canRefundShipping(OrderInterface $order) + { + return !abs($this->priceCurrency->round($order->getShippingAmount()) - $order->getShippingRefunded()) < .0001; + } + + /** + * @param CreditmemoInterface $creditmemo + * @param OrderInterface $order + * @return array + */ + private function getInvoiceQtysRefundLimits(CreditmemoInterface $creditmemo, OrderInterface $order) + { + $invoiceQtysRefundLimits = []; + if ($creditmemo->getInvoiceId() !== null) { + $invoiceQtysRefunded = []; + $invoice = $this->invoiceRepository->get($creditmemo->getInvoiceId()); + foreach ($order->getCreditmemosCollection() as $createdCreditmemo) { + if ( + $createdCreditmemo->getState() != Creditmemo::STATE_CANCELED && + $createdCreditmemo->getInvoiceId() == $invoice->getId() + ) { + foreach ($createdCreditmemo->getAllItems() as $createdCreditmemoItem) { + $orderItemId = $createdCreditmemoItem->getOrderItem()->getId(); + if (isset($invoiceQtysRefunded[$orderItemId])) { + $invoiceQtysRefunded[$orderItemId] += $createdCreditmemoItem->getQty(); + } else { + $invoiceQtysRefunded[$orderItemId] = $createdCreditmemoItem->getQty(); + } + } + } + } + + foreach ($invoice->getItems() as $invoiceItem) { + $invoiceQtyCanBeRefunded = $invoiceItem->getQty(); + $orderItemId = $invoiceItem->getOrderItem()->getId(); + if (isset($invoiceQtysRefunded[$orderItemId])) { + $invoiceQtyCanBeRefunded = $invoiceQtyCanBeRefunded - $invoiceQtysRefunded[$orderItemId]; + } + $invoiceQtysRefundLimits[$orderItemId] = $invoiceQtyCanBeRefunded; + } + } + + return $invoiceQtysRefundLimits; + } + + /** + * @param OrderInterface $order + * @return OrderItemInterface[] + */ + private function getOrderItems(OrderInterface $order) + { + $orderItemsById = []; + foreach ($order->getItems() as $item) { + $orderItemsById[$item->getItemId()] = $item; + } + + return $orderItemsById; + } + + /** + * @param Item $orderItem + * @param int $qty + * @return bool + */ + private function isQtyAvailable(Item $orderItem, $qty) + { + return $qty <= $orderItem->getQtyToRefund() || $orderItem->isDummy(); + } + + /** + * Check if order item can be refunded + * + * @param \Magento\Sales\Model\Order\Item $item + * @param double $qty + * @param array $invoiceQtysRefundLimits + * @return bool + */ + private function canRefundItem(\Magento\Sales\Model\Order\Item $item, $qty, array $invoiceQtysRefundLimits) + { + if ($item->isDummy()) { + return $this->canRefundDummyItem($item, $qty, $invoiceQtysRefundLimits); + } + + return $this->canRefundNoDummyItem($item, $invoiceQtysRefundLimits); + } + + /** + * Check if no dummy order item can be refunded + * + * @param \Magento\Sales\Model\Order\Item $item + * @param array $invoiceQtysRefundLimits + * @return bool + */ + private function canRefundNoDummyItem(\Magento\Sales\Model\Order\Item $item, array $invoiceQtysRefundLimits = []) + { + if ($item->getQtyToRefund() < 0) { + return false; + } + if (isset($invoiceQtysRefundLimits[$item->getId()])) { + return $invoiceQtysRefundLimits[$item->getId()] > 0; + } + return true; + } + + /** + * @param Item $item + * @param int $qty + * @param array $invoiceQtysRefundLimits + * @return bool + */ + private function canRefundDummyItem(\Magento\Sales\Model\Order\Item $item, $qty, array $invoiceQtysRefundLimits) + { + if ($item->getHasChildren()) { + foreach ($item->getChildrenItems() as $child) { + if ($this->canRefundRequestedQty($child, $qty, $invoiceQtysRefundLimits)) { + return true; + } + } + } elseif ($item->getParentItem()) { + return $this->canRefundRequestedQty($item->getParentItem(), $qty, $invoiceQtysRefundLimits); + } + + return false; + } + + /** + * @param Item $item + * @param int $qty + * @param array $invoiceQtysRefundLimits + * @return bool + */ + private function canRefundRequestedQty( + \Magento\Sales\Model\Order\Item $item, + $qty, + array $invoiceQtysRefundLimits + ) { + return $qty === null ? $this->canRefundNoDummyItem($item, $invoiceQtysRefundLimits) : $qty > 0; + } +} diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/TotalsValidator.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/TotalsValidator.php new file mode 100644 index 0000000000000..0fcdcc4d61c3e --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Validation/TotalsValidator.php @@ -0,0 +1,52 @@ +priceCurrency = $priceCurrency; + } + + /** + * @inheritDoc + */ + public function validate($entity) + { + $messages = []; + $baseOrderRefund = $this->priceCurrency->round( + $entity->getOrder()->getBaseTotalRefunded() + $entity->getBaseGrandTotal() + ); + if ($baseOrderRefund > $this->priceCurrency->round($entity->getOrder()->getBaseTotalPaid())) { + $baseAvailableRefund = $entity->getOrder()->getBaseTotalPaid() + - $entity->getOrder()->getBaseTotalRefunded(); + + $messages[] = __( + 'The most money available to refund is %1.', + $baseAvailableRefund + ); + } + + return $messages; + } +} diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php new file mode 100644 index 0000000000000..4d32dd653d03f --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/CreditmemoDocumentFactory.php @@ -0,0 +1,153 @@ +creditmemoFactory = $creditmemoFactory; + $this->commentFactory = $commentFactory; + $this->hydratorPool = $hydratorPool; + $this->orderRepository = $orderRepository; + } + + /** + * Get array with original data for new Creditmemo document + * + * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items + * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments + * @return array + */ + private function getCreditmemoCreationData( + array $items = [], + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null + ) { + $data = ['qtys' => []]; + foreach ($items as $item) { + $data['qtys'][$item->getOrderItemId()] = $item->getQty(); + } + if ($arguments) { + $hydrator = $this->hydratorPool->getHydrator( + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface::class + ); + $data = array_merge($hydrator->extract($arguments), $data); + } + return $data; + } + + /** + * Attach comment to the Creditmemo document. + * + * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo + * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment + * @param bool $appendComment + * @return \Magento\Sales\Api\Data\CreditmemoInterface + */ + private function attachComment( + \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo, + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment, + $appendComment = false + ) { + $commentData = $this->hydratorPool->getHydrator( + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface::class + )->extract($comment); + $comment = $this->commentFactory->create(['data' => $commentData]); + $comment->setParentId($creditmemo->getEntityId()) + ->setStoreId($creditmemo->getStoreId()) + ->setCreditmemo($creditmemo) + ->setIsCustomerNotified($appendComment); + $creditmemo->setComments([$comment]); + return $creditmemo; + + } + + /** + * Create new Creditmemo + * @param \Magento\Sales\Api\Data\OrderInterface $order + * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items + * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment + * @param bool|null $appendComment + * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments + * @return \Magento\Sales\Api\Data\CreditmemoInterface + */ + public function createFromOrder( + \Magento\Sales\Api\Data\OrderInterface $order, + array $items = [], + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + $appendComment = false, + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null + ) { + $data = $this->getCreditmemoCreationData($items, $arguments); + $creditmemo = $this->creditmemoFactory->createByOrder($order, $data); + if ($comment) { + $creditmemo = $this->attachComment($creditmemo, $comment, $appendComment); + } + return $creditmemo; + } + + /** + * @param \Magento\Sales\Api\Data\InvoiceInterface $invoice + * @param \Magento\Sales\Api\Data\CreditmemoItemCreationInterface[] $items + * @param \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface|null $comment + * @param bool|null $appendComment + * @param \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface|null $arguments + * @return \Magento\Sales\Api\Data\CreditmemoInterface + */ + public function createFromInvoice( + \Magento\Sales\Api\Data\InvoiceInterface $invoice, + array $items = [], + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + $appendComment = false, + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null + ) { + $data = $this->getCreditmemoCreationData($items, $arguments); + /** @var $invoice \Magento\Sales\Model\Order\Invoice */ + $invoice->setOrder($this->orderRepository->get($invoice->getOrderId())); + $creditmemo = $this->creditmemoFactory->createByInvoice($invoice, $data); + if ($comment) { + $creditmemo = $this->attachComment($creditmemo, $comment, $appendComment); + } + return $creditmemo; + } +} diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php index 21104933a51d6..75580cf93babe 100644 --- a/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php +++ b/app/code/Magento/Sales/Model/Order/CreditmemoFactory.php @@ -1,9 +1,8 @@ convertor = $convertOrderFactory->create(); $this->taxConfig = $taxConfig; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\Serialize\Serializer\Json::class + ); } /** @@ -57,7 +72,12 @@ public function createByOrder(\Magento\Sales\Model\Order $order, array $data = [ $item = $this->convertor->itemToCreditmemoItem($orderItem); if ($orderItem->isDummy()) { - $qty = 1; + if (isset($data['qtys'][$orderItem->getParentItemId()])) { + $parentQty = $data['qtys'][$orderItem->getParentItemId()]; + } else { + $parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1; + } + $qty = $this->calculateProductOptions($orderItem, $parentQty); $orderItem->setLockedDoShip(true); } else { if (isset($qtys[$orderItem->getId()])) { @@ -132,7 +152,12 @@ public function createByInvoice(\Magento\Sales\Model\Order\Invoice $invoice, arr $item = $this->convertor->itemToCreditmemoItem($orderItem); if ($orderItem->isDummy()) { - $qty = 1; + if (isset($data['qtys'][$orderItem->getParentItemId()])) { + $parentQty = $data['qtys'][$orderItem->getParentItemId()]; + } else { + $parentQty = $orderItem->getParentItem() ? $orderItem->getParentItem()->getQtyToRefund() : 1; + } + $qty = $this->calculateProductOptions($orderItem, $parentQty); } else { if (isset($qtys[$orderItem->getId()])) { $qty = (double)$qtys[$orderItem->getId()]; @@ -245,4 +270,23 @@ protected function initData($creditmemo, $data) $creditmemo->setAdjustmentNegative($data['adjustment_negative']); } } + + /** + * @param \Magento\Sales\Api\Data\OrderItemInterface $orderItem + * @param int $parentQty + * @return int + */ + private function calculateProductOptions(\Magento\Sales\Api\Data\OrderItemInterface $orderItem, $parentQty) + { + $qty = $parentQty; + $productOptions = $orderItem->getProductOptions(); + if (isset($productOptions['bundle_selection_attributes'])) { + $bundleSelectionAttributes = $this->serializer + ->unserialize($productOptions['bundle_selection_attributes']); + if ($bundleSelectionAttributes) { + $qty = $bundleSelectionAttributes['qty'] * $parentQty; + } + } + return $qty; + } } diff --git a/app/code/Magento/Sales/Model/Order/CreditmemoNotifier.php b/app/code/Magento/Sales/Model/Order/CreditmemoNotifier.php index 32ca016728a24..4b3ffd9d3e3b2 100644 --- a/app/code/Magento/Sales/Model/Order/CreditmemoNotifier.php +++ b/app/code/Magento/Sales/Model/Order/CreditmemoNotifier.php @@ -1,6 +1,6 @@ gridPool = $gridPool; + $this->attribute = $attribute; + } + + /** + * @param \Magento\Sales\Model\ResourceModel\Order\Handler\Address $subject + * @param \Magento\Sales\Model\ResourceModel\Order\Handler\Address $result + * @param \Magento\Sales\Model\Order $order + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterProcess( + \Magento\Sales\Model\ResourceModel\Order\Handler\Address $subject, + \Magento\Sales\Model\ResourceModel\Order\Handler\Address $result, + \Magento\Sales\Model\Order $order + ) { + if ($order->hasInvoices()) { + $billingAddress = $order->getBillingAddress(); + $shippingAddress = $order->getShippingAddress(); + + $orderInvoiceHasChanges = false; + /** @var \Magento\Sales\Model\Order\Invoice $invoice */ + foreach ($order->getInvoiceCollection()->getItems() as $invoice) { + $invoiceAttributesForSave = []; + + if (!$invoice->getBillingAddressId() && $billingAddress) { + $invoice->setBillingAddressId($billingAddress->getId()); + $invoiceAttributesForSave[] = 'billing_address_id'; + $orderInvoiceHasChanges = true; + } + + if (!$invoice->getShippingAddressId() && $shippingAddress) { + $invoice->setShippingAddressId($shippingAddress->getId()); + $invoiceAttributesForSave[] = 'shipping_address_id'; + $orderInvoiceHasChanges = true; + } + + if (!empty($invoiceAttributesForSave)) { + $this->attribute->saveAttribute($invoice, $invoiceAttributesForSave); + } + } + + if ($orderInvoiceHasChanges) { + $this->gridPool->refreshByOrderId($order->getId()); + } + } + } +} diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php index 2677ee400f5b4..2da96b5a3921a 100644 --- a/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php +++ b/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php @@ -1,6 +1,6 @@ paymentRepository = $paymentRepository; + $this->orderRepository = $orderRepository; + } + + /** + * @inheritdoc + */ + public function validate($entity) + { + if ( + $entity->getState() == Invoice::STATE_PAID && + $this->isGrandTotalEnoughToRefund($entity) && + $this->isPaymentAllowRefund($entity) + ) { + return []; + } + + return [__('We can\'t create creditmemo for the invoice.')]; + } + + /** + * @param InvoiceInterface $invoice + * @return bool + */ + private function isPaymentAllowRefund(InvoiceInterface $invoice) + { + $order = $this->orderRepository->get($invoice->getOrderId()); + $payment = $order->getPayment(); + if (!$payment instanceof InfoInterface) { + return false; + } + $method = $payment->getMethodInstance(); + return $this->canPartialRefund($method, $payment) || $this->canFullRefund($invoice, $method); + } + + /** + * @param InvoiceInterface $entity + * @return bool + */ + private function isGrandTotalEnoughToRefund(InvoiceInterface $entity) + { + return abs($entity->getBaseGrandTotal() - $entity->getBaseTotalRefunded()) >= .0001; + } + + /** + * @param MethodInterface $method + * @param InfoInterface $payment + * @return bool + */ + private function canPartialRefund(MethodInterface $method, InfoInterface $payment) + { + return $method->canRefund() && + $method->canRefundPartialPerInvoice() && + $payment->getAmountPaid() > $payment->getAmountRefunded(); + } + + /** + * @param InvoiceInterface $invoice + * @param MethodInterface $method + * @return bool + */ + private function canFullRefund(InvoiceInterface $invoice, MethodInterface $method) + { + return $method->canRefund() && !$invoice->getIsUsedForRefund(); + } +} diff --git a/app/code/Magento/Sales/Model/Order/InvoiceDocumentFactory.php b/app/code/Magento/Sales/Model/Order/InvoiceDocumentFactory.php index be5995ec61e4f..bac17856efd35 100644 --- a/app/code/Magento/Sales/Model/Order/InvoiceDocumentFactory.php +++ b/app/code/Magento/Sales/Model/Order/InvoiceDocumentFactory.php @@ -1,6 +1,6 @@ serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); $this->_orderFactory = $orderFactory; $this->_storeManager = $storeManager; $this->productRepository = $productRepository; @@ -466,7 +477,7 @@ public function setProductOptions(array $options = null) public function getProductOptions() { $data = $this->_getData('product_options'); - return is_string($data) ? unserialize($data) : $data; + return is_string($data) ? $this->serializer->unserialize($data) : $data; } /** diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index 8fdeca7eb7d03..1ec91db1703c2 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -1,6 +1,6 @@ transactionManager->generateTransactionId($this, Transaction::TYPE_REFUND) ); - // call refund from gateway if required $isOnline = false; $gateway = $this->getMethodInstance(); $invoice = null; - if ($gateway->canRefund() && $creditmemo->getDoTransaction()) { + if ($gateway->canRefund()) { $this->setCreditmemo($creditmemo); - $invoice = $creditmemo->getInvoice(); - if ($invoice) { - $isOnline = true; - $captureTxn = $this->transactionRepository->getByTransactionId( - $invoice->getTransactionId(), - $this->getId(), - $this->getOrder()->getId() - ); - if ($captureTxn) { - $this->setTransactionIdsForRefund($captureTxn); - } - $this->setShouldCloseParentTransaction(true); - // TODO: implement multiple refunds per capture - try { - $gateway->setStore( - $this->getOrder()->getStoreId() + if ($creditmemo->getDoTransaction()) { + $invoice = $creditmemo->getInvoice(); + if ($invoice) { + $isOnline = true; + $captureTxn = $this->transactionRepository->getByTransactionId( + $invoice->getTransactionId(), + $this->getId(), + $this->getOrder()->getId() ); - $this->setRefundTransactionId($invoice->getTransactionId()); - $gateway->refund($this, $baseAmountToRefund); - - $creditmemo->setTransactionId($this->getLastTransId()); - } catch (\Magento\Framework\Exception\LocalizedException $e) { - if (!$captureTxn) { - throw new \Magento\Framework\Exception\LocalizedException( - __('If the invoice was created offline, try creating an offline credit memo.'), - $e + if ($captureTxn) { + $this->setTransactionIdsForRefund($captureTxn); + } + $this->setShouldCloseParentTransaction(true); + // TODO: implement multiple refunds per capture + try { + $gateway->setStore( + $this->getOrder()->getStoreId() ); + $this->setRefundTransactionId($invoice->getTransactionId()); + $gateway->refund($this, $baseAmountToRefund); + + $creditmemo->setTransactionId($this->getLastTransId()); + } catch (\Magento\Framework\Exception\LocalizedException $e) { + if (!$captureTxn) { + throw new \Magento\Framework\Exception\LocalizedException( + __('If the invoice was created offline, try creating an offline credit memo.'), + $e + ); + } + throw $e; } - throw $e; } + } else if ($gateway->isOffline()) { + $gateway->setStore( + $this->getOrder()->getStoreId() + ); + $gateway->refund($this, $baseAmountToRefund); } } @@ -692,7 +704,12 @@ public function refund($creditmemo) } $message = $message = $this->prependMessage($message); $message = $this->_appendTransactionToMessage($transaction, $message); - $this->setOrderStateProcessing($message); + $orderState = $this->getOrderStateResolver()->getStateForOrder($this->getOrder()); + $this->getOrder() + ->addStatusHistoryComment( + $message, + $this->getOrder()->getConfig()->getStateDefaultStatus($orderState) + )->setIsCustomerNotified($creditmemo->getOrder()->getCustomerNoteNotify()); $this->_eventManager->dispatch( 'sales_order_payment_refund', ['payment' => $this, 'creditmemo' => $creditmemo] @@ -1272,7 +1289,7 @@ public function getAuthorizationTransaction() */ public function isCaptureFinal($amountToCapture) { - $total = $this->getOrder()->getTotalDue(); + $total = $this->getOrder()->getBaseTotalDue(); return $this->formatAmount($total, true) == $this->formatAmount($amountToCapture, true); } @@ -1388,6 +1405,19 @@ protected function _getInvoiceForTransactionId($transactionId) return false; } + /** + * @deprecated + * @return OrderStateResolverInterface + */ + private function getOrderStateResolver() + { + if ($this->orderStateResolver === null) { + $this->orderStateResolver = ObjectManager::getInstance()->get(OrderStateResolverInterface::class); + } + + return$this->orderStateResolver; + } + //@codeCoverageIgnoreStart /** * Returns account_status diff --git a/app/code/Magento/Sales/Model/Order/Payment/Info.php b/app/code/Magento/Sales/Model/Order/Payment/Info.php index 4e5dfee783aa2..89f02cb874802 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Info.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Info.php @@ -1,6 +1,6 @@ drawText(__('Order # ') . $order->getRealOrderId(), 35, $top -= 30, 'UTF-8'); + $top +=15; } + + $top -=30; $page->drawText( __('Order Date: ') . $this->_localeDate->formatDate( @@ -408,7 +411,7 @@ protected function insertOrder(&$page, $obj, $putOrderId = true) false ), 35, - $top -= 15, + $top, 'UTF-8' ); diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Config.php b/app/code/Magento/Sales/Model/Order/Pdf/Config.php index e44a180bf850f..603577aad61bd 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Config.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Config.php @@ -2,7 +2,7 @@ /** * Pdf config * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Sales\Model\Order\Pdf; diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Config/Converter.php b/app/code/Magento/Sales/Model/Order/Pdf/Config/Converter.php index 8ced98a54a580..fd26d15ba69bf 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Config/Converter.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Config/Converter.php @@ -2,7 +2,7 @@ /** * Converter of pdf configuration from \DOMDocument to array * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Sales\Model\Order\Pdf\Config; diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Config/Reader.php b/app/code/Magento/Sales/Model/Order/Pdf/Config/Reader.php index 954a91ed64212..3ffe8d45535ae 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Config/Reader.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Config/Reader.php @@ -2,7 +2,7 @@ /** * Loads catalog attributes configuration from multiple XML files by merging them together * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Sales\Model\Order\Pdf\Config; diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Config/SchemaLocator.php b/app/code/Magento/Sales/Model/Order/Pdf/Config/SchemaLocator.php index 74a329c0882ed..0f138a0714605 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Config/SchemaLocator.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Config/SchemaLocator.php @@ -2,7 +2,7 @@ /** * Attributes config schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Sales\Model\Order\Pdf\Config; diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Pdf/Creditmemo.php index 0df90deed847a..71d64ed575d0d 100644 --- a/app/code/Magento/Sales/Model/Order/Pdf/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Pdf/Creditmemo.php @@ -1,6 +1,6 @@ converter = $convertOrderFactory->create(); $this->trackFactory = $trackFactory; $this->instanceName = \Magento\Sales\Api\Data\ShipmentInterface::class; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(Json::class); } /** @@ -100,7 +112,7 @@ protected function prepareItems( $productOptions = $orderItem->getProductOptions(); if (isset($productOptions['bundle_selection_attributes'])) { - $bundleSelectionAttributes = unserialize( + $bundleSelectionAttributes = $this->serializer->unserialize( $productOptions['bundle_selection_attributes'] ); diff --git a/app/code/Magento/Sales/Model/Order/ShipmentRepository.php b/app/code/Magento/Sales/Model/Order/ShipmentRepository.php index 2ddff08d90060..9ccd9df1c2574 100644 --- a/app/code/Magento/Sales/Model/Order/ShipmentRepository.php +++ b/app/code/Magento/Sales/Model/Order/ShipmentRepository.php @@ -1,6 +1,6 @@ _orderTotalFactory = $orderTotalFactory; } diff --git a/app/code/Magento/Sales/Model/Order/TotalFactory.php b/app/code/Magento/Sales/Model/Order/TotalFactory.php index 635113b48c767..7cdc948dcead9 100644 --- a/app/code/Magento/Sales/Model/Order/TotalFactory.php +++ b/app/code/Magento/Sales/Model/Order/TotalFactory.php @@ -1,6 +1,6 @@ priceCurrency = $priceCurrency; + } + + /** + * @inheritdoc + */ + public function validate($entity) + { + $messages = []; + if ($entity->getState() === Order::STATE_PAYMENT_REVIEW || + $entity->getState() === Order::STATE_HOLDED || + $entity->getState() === Order::STATE_CANCELED || + $entity->getState() === Order::STATE_CLOSED + ) { + $messages[] = __( + 'A creditmemo can not be created when an order has a status of %1', + $entity->getStatus() + ); + } elseif (!$this->isTotalPaidEnoughForRefund($entity)) { + $messages[] = __('The order does not allow a creditmemo to be created.'); + } + + return $messages; + } + + /** + * We can have problem with float in php (on some server $a=762.73;$b=762.73; $a-$b!=0) + * for this we have additional diapason for 0 + * TotalPaid - contains amount, that were not rounded. + * + * @param OrderInterface $order + * @return bool + */ + private function isTotalPaidEnoughForRefund(OrderInterface $order) + { + return !abs($this->priceCurrency->round($order->getTotalPaid()) - $order->getTotalRefunded()) < .0001; + } +} diff --git a/app/code/Magento/Sales/Model/Order/Validation/CanShip.php b/app/code/Magento/Sales/Model/Order/Validation/CanShip.php index 46638a62483e6..0f5f17e0ab251 100644 --- a/app/code/Magento/Sales/Model/Order/Validation/CanShip.php +++ b/app/code/Magento/Sales/Model/Order/Validation/CanShip.php @@ -1,6 +1,6 @@ invoiceValidator = $invoiceValidator; + $this->orderValidator = $orderValidator; + $this->validatorResultMerger = $validatorResultMerger; + } + + /** + * @inheritdoc + */ + public function validate( + OrderInterface $order, + InvoiceInterface $invoice, + $capture = false, + array $items = [], + $notify = false, + $appendComment = false, + InvoiceCommentCreationInterface $comment = null, + InvoiceCreationArgumentsInterface $arguments = null + ) { + return $this->validatorResultMerger->merge( + $this->invoiceValidator->validate( + $invoice, + [InvoiceQuantityValidator::class] + ), + $this->orderValidator->validate( + $order, + [CanInvoice::class] + ) + ); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrderInterface.php b/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrderInterface.php new file mode 100644 index 0000000000000..d04cc26bce321 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Validation/InvoiceOrderInterface.php @@ -0,0 +1,42 @@ +orderValidator = $orderValidator; + $this->creditmemoValidator = $creditmemoValidator; + $this->itemCreationValidator = $itemCreationValidator; + $this->invoiceValidator = $invoiceValidator; + $this->validatorResultMerger = $validatorResultMerger; + } + + /** + * @inheritdoc + */ + public function validate( + InvoiceInterface $invoice, + OrderInterface $order, + CreditmemoInterface $creditmemo, + array $items = [], + $isOnline = false, + $notify = false, + $appendComment = false, + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null + ) { + $orderValidationResult = $this->orderValidator->validate( + $order, + [ + CanRefund::class + ] + ); + $creditmemoValidationResult = $this->creditmemoValidator->validate( + $creditmemo, + [ + QuantityValidator::class, + TotalsValidator::class + ] + ); + + $itemsValidation = []; + foreach ($items as $item) { + $itemsValidation[] = $this->itemCreationValidator->validate( + $item, + [CreationQuantityValidator::class], + $order + )->getMessages(); + } + + $invoiceValidationResult = $this->invoiceValidator->validate( + $invoice, + [ + \Magento\Sales\Model\Order\Invoice\Validation\CanRefund::class + ] + ); + + return $this->validatorResultMerger->merge( + $orderValidationResult, + $creditmemoValidationResult, + $invoiceValidationResult->getMessages(), + ...$itemsValidation + ); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Validation/RefundInvoiceInterface.php b/app/code/Magento/Sales/Model/Order/Validation/RefundInvoiceInterface.php new file mode 100644 index 0000000000000..28ae43f46b84f --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Validation/RefundInvoiceInterface.php @@ -0,0 +1,43 @@ +orderValidator = $orderValidator; + $this->creditmemoValidator = $creditmemoValidator; + $this->itemCreationValidator = $itemCreationValidator; + $this->validatorResultMerger = $validatorResultMerger; + } + + /** + * @inheritdoc + */ + public function validate( + OrderInterface $order, + CreditmemoInterface $creditmemo, + array $items = [], + $notify = false, + $appendComment = false, + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null + ) { + $orderValidationResult = $this->orderValidator->validate( + $order, + [ + CanRefund::class + ] + ); + $creditmemoValidationResult = $this->creditmemoValidator->validate( + $creditmemo, + [ + QuantityValidator::class, + TotalsValidator::class + ] + ); + + $itemsValidation = []; + foreach ($items as $item) { + $itemsValidation[] = $this->itemCreationValidator->validate( + $item, + [CreationQuantityValidator::class], + $order + )->getMessages(); + } + + return $this->validatorResultMerger->merge( + $orderValidationResult, + $creditmemoValidationResult, + ...$itemsValidation + ); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Validation/RefundOrderInterface.php b/app/code/Magento/Sales/Model/Order/Validation/RefundOrderInterface.php new file mode 100644 index 0000000000000..678d199489faf --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Validation/RefundOrderInterface.php @@ -0,0 +1,38 @@ +orderValidator = $orderValidator; + $this->shipmentValidator = $shipmentValidator; + $this->validatorResultMerger = $validatorResultMerger; + } + + /** + * @param OrderInterface $order + * @param ShipmentInterface $shipment + * @param array $items + * @param bool $notify + * @param bool $appendComment + * @param \Magento\Sales\Api\Data\ShipmentCommentCreationInterface|null $comment + * @param array $tracks + * @param array $packages + * @param \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface|null $arguments + * @return \Magento\Sales\Model\ValidatorResultInterface + */ + public function validate( + $order, + $shipment, + array $items = [], + $notify = false, + $appendComment = false, + \Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null, + array $tracks = [], + array $packages = [], + \Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface $arguments = null + ) { + $orderValidationResult = $this->orderValidator->validate( + $order, + [ + CanShip::class + ] + ); + $shipmentValidationResult = $this->shipmentValidator->validate( + $shipment, + [ + QuantityValidator::class, + TrackValidator::class + ] + ); + + return $this->validatorResultMerger->merge($orderValidationResult, $shipmentValidationResult); + } +} diff --git a/app/code/Magento/Sales/Model/Order/Validation/ShipOrderInterface.php b/app/code/Magento/Sales/Model/Order/Validation/ShipOrderInterface.php new file mode 100644 index 0000000000000..b471f4f5edaac --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Validation/ShipOrderInterface.php @@ -0,0 +1,41 @@ +getExtensionAttributes(); + if ($entity->getIsNotVirtual() && $extensionAttributes && $extensionAttributes->getShippingAssignments()) { + $shippingAssignments = $extensionAttributes->getShippingAssignments(); + if (!empty($shippingAssignments)) { + $shipping = array_shift($shippingAssignments)->getShipping(); + $entity->setShippingAddress($shipping->getAddress()); + $entity->setShippingMethod($shipping->getMethod()); + } + } $this->metadata->getMapper()->save($entity); $this->registry[$entity->getEntityId()] = $entity; return $this->registry[$entity->getEntityId()]; diff --git a/app/code/Magento/Sales/Model/RefundInvoice.php b/app/code/Magento/Sales/Model/RefundInvoice.php new file mode 100644 index 0000000000000..e2b09eb4ce6fe --- /dev/null +++ b/app/code/Magento/Sales/Model/RefundInvoice.php @@ -0,0 +1,198 @@ +resourceConnection = $resourceConnection; + $this->orderStateResolver = $orderStateResolver; + $this->orderRepository = $orderRepository; + $this->invoiceRepository = $invoiceRepository; + $this->validator = $validator; + $this->creditmemoRepository = $creditmemoRepository; + $this->paymentAdapter = $paymentAdapter; + $this->creditmemoDocumentFactory = $creditmemoDocumentFactory; + $this->notifier = $notifier; + $this->config = $config; + $this->logger = $logger; + } + + /** + * @inheritdoc + */ + public function execute( + $invoiceId, + array $items = [], + $isOnline = false, + $notify = false, + $appendComment = false, + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null + ) { + $connection = $this->resourceConnection->getConnection('sales'); + $invoice = $this->invoiceRepository->get($invoiceId); + $order = $this->orderRepository->get($invoice->getOrderId()); + $creditmemo = $this->creditmemoDocumentFactory->createFromInvoice( + $invoice, + $items, + $comment, + ($appendComment && $notify), + $arguments + ); + + $validationMessages = $this->validator->validate( + $invoice, + $order, + $creditmemo, + $items, + $isOnline, + $notify, + $appendComment, + $comment, + $arguments + ); + if ($validationMessages->hasMessages()) { + throw new \Magento\Sales\Exception\DocumentValidationException( + __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages->getMessages())) + ); + } + $connection->beginTransaction(); + try { + $creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED); + $order->setCustomerNoteNotify($notify); + $order = $this->paymentAdapter->refund($creditmemo, $order, $isOnline); + $order->setState( + $this->orderStateResolver->getStateForOrder($order, []) + ); + $order->setStatus($this->config->getStateDefaultStatus($order->getState())); + if (!$isOnline) { + $invoice->setIsUsedForRefund(true); + $invoice->setBaseTotalRefunded( + $invoice->getBaseTotalRefunded() + $creditmemo->getBaseGrandTotal() + ); + } + $this->invoiceRepository->save($invoice); + $order = $this->orderRepository->save($order); + $creditmemo = $this->creditmemoRepository->save($creditmemo); + $connection->commit(); + } catch (\Exception $e) { + $this->logger->critical($e); + $connection->rollBack(); + throw new \Magento\Sales\Exception\CouldNotRefundException( + __('Could not save a Creditmemo, see error log for details') + ); + } + if ($notify) { + if (!$appendComment) { + $comment = null; + } + $this->notifier->notify($order, $creditmemo, $comment); + } + + return $creditmemo->getEntityId(); + } +} diff --git a/app/code/Magento/Sales/Model/RefundOrder.php b/app/code/Magento/Sales/Model/RefundOrder.php new file mode 100644 index 0000000000000..2392fe9234381 --- /dev/null +++ b/app/code/Magento/Sales/Model/RefundOrder.php @@ -0,0 +1,178 @@ +resourceConnection = $resourceConnection; + $this->orderStateResolver = $orderStateResolver; + $this->orderRepository = $orderRepository; + $this->creditmemoRepository = $creditmemoRepository; + $this->paymentAdapter = $paymentAdapter; + $this->creditmemoDocumentFactory = $creditmemoDocumentFactory; + $this->validator = $validator; + $this->notifier = $notifier; + $this->config = $config; + $this->logger = $logger; + } + + /** + * @inheritdoc + */ + public function execute( + $orderId, + array $items = [], + $notify = false, + $appendComment = false, + \Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null, + \Magento\Sales\Api\Data\CreditmemoCreationArgumentsInterface $arguments = null + ) { + $connection = $this->resourceConnection->getConnection('sales'); + $order = $this->orderRepository->get($orderId); + $creditmemo = $this->creditmemoDocumentFactory->createFromOrder( + $order, + $items, + $comment, + ($appendComment && $notify), + $arguments + ); + $validationMessages = $this->validator->validate( + $order, + $creditmemo, + $items, + $notify, + $appendComment, + $comment, + $arguments + ); + if ($validationMessages->hasMessages()) { + throw new \Magento\Sales\Exception\DocumentValidationException( + __("Creditmemo Document Validation Error(s):\n" . implode("\n", $validationMessages->getMessages())) + ); + } + $connection->beginTransaction(); + try { + $creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED); + $order->setCustomerNoteNotify($notify); + $order = $this->paymentAdapter->refund($creditmemo, $order); + $order->setState( + $this->orderStateResolver->getStateForOrder($order, []) + ); + $order->setStatus($this->config->getStateDefaultStatus($order->getState())); + + $order = $this->orderRepository->save($order); + $creditmemo = $this->creditmemoRepository->save($creditmemo); + $connection->commit(); + } catch (\Exception $e) { + $this->logger->critical($e); + $connection->rollBack(); + throw new \Magento\Sales\Exception\CouldNotRefundException( + __('Could not save a Creditmemo, see error log for details') + ); + } + if ($notify) { + if (!$appendComment) { + $comment = null; + } + $this->notifier->notify($order, $creditmemo, $comment); + } + + return $creditmemo->getEntityId(); + } +} diff --git a/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php b/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php index 3799e681757f2..10cbb175c70bc 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php +++ b/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php @@ -1,6 +1,6 @@ objectManager = $objectManager; $this->instanceName = $instanceName; diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactoryInterface.php b/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactoryInterface.php index 27a9a640906b2..3504e124ab85d 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactoryInterface.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/CollectionFactoryInterface.php @@ -1,6 +1,6 @@ commit(); } catch (\Exception $e) { $connection->rollBack(); - throw new \Magento\Framework\Exception\LocalizedException($e->getMessage()); + throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage())); } return $creditmemo; diff --git a/app/code/Magento/Sales/Model/Service/InvoiceService.php b/app/code/Magento/Sales/Model/Service/InvoiceService.php index ac66d4dc32f4c..2af5acb3f7d20 100644 --- a/app/code/Magento/Sales/Model/Service/InvoiceService.php +++ b/app/code/Magento/Sales/Model/Service/InvoiceService.php @@ -1,6 +1,6 @@ resourceConnection = $resourceConnection; $this->orderRepository = $orderRepository; $this->shipmentDocumentFactory = $shipmentDocumentFactory; - $this->shipmentValidator = $shipmentValidator; - $this->orderValidator = $orderValidator; $this->orderStateResolver = $orderStateResolver; $this->config = $config; $this->shipmentRepository = $shipmentRepository; + $this->shipOrderValidator = $shipOrderValidator; $this->notifierInterface = $notifierInterface; $this->logger = $logger; $this->orderRegistrar = $orderRegistrar; @@ -159,23 +147,19 @@ public function execute( $packages, $arguments ); - $orderValidationResult = $this->orderValidator->validate( + $validationMessages = $this->shipOrderValidator->validate( $order, - [ - CanShip::class - ] - ); - $shipmentValidationResult = $this->shipmentValidator->validate( $shipment, - [ - QuantityValidator::class, - TrackValidator::class - ] + $items, + $notify, + $appendComment, + $comment, + $tracks, + $packages ); - $validationMessages = array_merge($orderValidationResult, $shipmentValidationResult); - if (!empty($validationMessages)) { + if ($validationMessages->hasMessages()) { throw new \Magento\Sales\Exception\DocumentValidationException( - __("Shipment Document Validation Error(s):\n" . implode("\n", $validationMessages)) + __("Shipment Document Validation Error(s):\n" . implode("\n", $validationMessages->getMessages())) ); } $connection->beginTransaction(); diff --git a/app/code/Magento/Sales/Model/Spi/CreditmemoCommentResourceInterface.php b/app/code/Magento/Sales/Model/Spi/CreditmemoCommentResourceInterface.php index 414c406f56401..f592a03c35351 100644 --- a/app/code/Magento/Sales/Model/Spi/CreditmemoCommentResourceInterface.php +++ b/app/code/Magento/Sales/Model/Spi/CreditmemoCommentResourceInterface.php @@ -1,6 +1,6 @@ objectManager = $objectManager; + $this->validatorResultFactory = $validatorResult; } /** * @param object $entity * @param ValidatorInterface[] $validators - * @return string[] + * @param object|null $context + * @return ValidatorResultInterface * @throws ConfigurationMismatchException */ - public function validate($entity, array $validators) + public function validate($entity, array $validators, $context = null) { $messages = []; + $validatorArguments = []; + if ($context !== null) { + $validatorArguments['context'] = $context; + } + foreach ($validators as $validatorName) { - $validator = $this->objectManager->get($validatorName); + $validator = $this->objectManager->create($validatorName, $validatorArguments); if (!$validator instanceof ValidatorInterface) { throw new ConfigurationMismatchException( __( @@ -50,7 +65,11 @@ public function validate($entity, array $validators) } $messages = array_merge($messages, $validator->validate($entity)); } + $validationResult = $this->validatorResultFactory->create(); + foreach ($messages as $message) { + $validationResult->addMessage($message); + } - return $messages; + return $validationResult; } } diff --git a/app/code/Magento/Sales/Model/ValidatorInterface.php b/app/code/Magento/Sales/Model/ValidatorInterface.php index 1882782e314f7..b0d3420caec4a 100644 --- a/app/code/Magento/Sales/Model/ValidatorInterface.php +++ b/app/code/Magento/Sales/Model/ValidatorInterface.php @@ -1,6 +1,6 @@ messages[] = (string)$message; + } + + /** + * @return bool + */ + public function hasMessages() + { + return count($this->messages) > 0; + } + + /** + * @return \string[] + */ + public function getMessages() + { + return $this->messages; + } +} diff --git a/app/code/Magento/Sales/Model/ValidatorResultInterface.php b/app/code/Magento/Sales/Model/ValidatorResultInterface.php new file mode 100644 index 0000000000000..990861417b7ed --- /dev/null +++ b/app/code/Magento/Sales/Model/ValidatorResultInterface.php @@ -0,0 +1,29 @@ +validatorResultInterfaceFactory = $validatorResultInterfaceFactory; + } + + /** + * Merge two validator results and additional messages + * + * @param ValidatorResultInterface $first + * @param ValidatorResultInterface $second + * @param \string[] $validatorMessages + * @return ValidatorResultInterface + */ + public function merge(ValidatorResultInterface $first, ValidatorResultInterface $second, ... $validatorMessages) + { + $messages = array_merge($first->getMessages(), $second->getMessages(), ...$validatorMessages); + + $result = $this->validatorResultInterfaceFactory->create(); + foreach ($messages as $message) { + $result->addMessage($message); + } + + return $result; + } +} diff --git a/app/code/Magento/Sales/Observer/Backend/CatalogPriceRule.php b/app/code/Magento/Sales/Observer/Backend/CatalogPriceRule.php index 9f1bf17fa117d..64fffc382a60c 100644 --- a/app/code/Magento/Sales/Observer/Backend/CatalogPriceRule.php +++ b/app/code/Magento/Sales/Observer/Backend/CatalogPriceRule.php @@ -1,6 +1,6 @@ 'sales_order_item', + 'identifier' => 'item_id', + 'title' => 'product_options', + 'data_converter' => SerializedDataConverter::class + ], + [ + 'table' => 'sales_shipment', + 'identifier' => 'entity_id', + 'title' => 'packages', + 'data_converter' => SerializedToJson::class + ], + [ + 'table' => 'sales_order_payment', + 'identifier' => 'entity_id', + 'title' => 'additional_information', + 'data_converter' => SerializedToJson::class + ], + [ + 'table' => 'sales_payment_transaction', + 'identifier' => 'transaction_id', + 'title' => 'additional_information', + 'data_converter' => SerializedToJson::class + ] + ]; + + /** + * Constructor + * + * @param SalesSetup $salesSetup + * @param FieldDataConverterFactory $fieldDataConverterFactory + */ + public function __construct( + SalesSetup $salesSetup, + FieldDataConverterFactory $fieldDataConverterFactory + ) { + $this->salesSetup = $salesSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + } + + /** + * Convert data for the following fields from serialized to JSON format: + * sales_order_item.product_options + * sales_shipment.packages + * sales_order_payment.additional_information + * sales_payment_transaction.additional_information + * + * @return void + */ + public function convert() + { + foreach ($this->fieldsToUpdate as $field) { + $fieldDataConverter = $this->getFieldDataConverter($field['data_converter']); + $fieldDataConverter->convert( + $this->salesSetup->getConnection(), + $this->salesSetup->getTable($field['table']), + $field['identifier'], + $field['title'] + ); + } + } + + /** + * Get field data converter + * + * @param string $dataConverterClassName + * @return FieldDataConverter + */ + private function getFieldDataConverter($dataConverterClassName) + { + if (!isset($this->fieldDataConverters[$dataConverterClassName])) { + $this->fieldDataConverters[$dataConverterClassName] = $this->fieldDataConverterFactory->create( + $dataConverterClassName + ); + } + return $this->fieldDataConverters[$dataConverterClassName]; + } +} diff --git a/app/code/Magento/Sales/Setup/InstallData.php b/app/code/Magento/Sales/Setup/InstallData.php index a1bc265cec6e3..38e5446a12a33 100644 --- a/app/code/Magento/Sales/Setup/InstallData.php +++ b/app/code/Magento/Sales/Setup/InstallData.php @@ -1,6 +1,6 @@ addColumn( 'cc_number_enc', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 32, + 128, [], 'Cc Number Enc' )->addColumn( diff --git a/app/code/Magento/Sales/Setup/SalesSetup.php b/app/code/Magento/Sales/Setup/SalesSetup.php index 3a2c999678a03..3227688beba2c 100644 --- a/app/code/Magento/Sales/Setup/SalesSetup.php +++ b/app/code/Magento/Sales/Setup/SalesSetup.php @@ -1,6 +1,6 @@ getSetup()->getConnection(self::$connectionName)->listTables(); + $tablesList = $this->getConnection() + ->listTables(); return in_array( - strtoupper($this->getSetup()->getTable($table, self::$connectionName)), + strtoupper($this->getTable($table)), array_map('strtoupper', $tablesList) ); } @@ -152,15 +157,14 @@ public function addAttribute($entityTypeId, $code, array $attr) */ protected function _addFlatAttribute($table, $attribute, $attr) { - $tableInfo = $this->getSetup() - ->getConnection(self::$connectionName) - ->describeTable($this->getSetup()->getTable($table, self::$connectionName)); + $tableInfo = $this->getConnection() + ->describeTable($this->getTable($table)); if (isset($tableInfo[$attribute])) { return $this; } $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr); - $this->getSetup()->getConnection(self::$connectionName)->addColumn( - $this->getSetup()->getTable($table, self::$connectionName), + $this->getConnection()->addColumn( + $this->getTable($table), $attribute, $columnDefinition ); @@ -180,8 +184,8 @@ protected function _addGridAttribute($table, $attribute, $attr, $entityTypeId) { if (in_array($entityTypeId, $this->_flatEntitiesGrid) && !empty($attr['grid'])) { $columnDefinition = $this->_getAttributeColumnDefinition($attribute, $attr); - $this->getSetup()->getConnection(self::$connectionName)->addColumn( - $this->getSetup()->getTable($table . '_grid', self::$connectionName), + $this->getConnection()->addColumn( + $this->getTable($table . '_grid'), $attribute, $columnDefinition ); @@ -297,4 +301,25 @@ public function getEncryptor() { return $this->encryptor; } + + /** + * Get sales connection + * + * @return \Magento\Framework\DB\Adapter\AdapterInterface + */ + public function getConnection() + { + return $this->getSetup()->getConnection(self::$connectionName); + } + + /** + * Get table name + * + * @param string $table + * @return string + */ + public function getTable($table) + { + return $this->getSetup()->getTable($table, self::$connectionName); + } } diff --git a/app/code/Magento/Sales/Setup/SerializedDataConverter.php b/app/code/Magento/Sales/Setup/SerializedDataConverter.php new file mode 100644 index 0000000000000..57c564f488cff --- /dev/null +++ b/app/code/Magento/Sales/Setup/SerializedDataConverter.php @@ -0,0 +1,70 @@ +serialize = $serialize; + $this->json = $json; + } + + /** + * Convert from serialized to JSON format. + * + * @param string $value + * @return string + */ + public function convert($value) + { + $valueUnserialized = $this->serialize->unserialize($value); + if (isset($valueUnserialized['options'])) { + foreach ($valueUnserialized['options'] as $key => $option) { + if ($option['option_type'] === 'file') { + $valueUnserialized['options'][$key]['option_value'] = $this->json->serialize( + $this->serialize->unserialize( + $option['option_value'] + ) + ); + } + } + } + if (isset($valueUnserialized['bundle_selection_attributes'])) { + $valueUnserialized['bundle_selection_attributes'] = $this->json->serialize( + $this->serialize->unserialize( + $valueUnserialized['bundle_selection_attributes'] + ) + ); + } + return $this->json->serialize($valueUnserialized); + } +} diff --git a/app/code/Magento/Sales/Setup/UpgradeData.php b/app/code/Magento/Sales/Setup/UpgradeData.php index 9580dd8a667a0..004ea58c808d7 100644 --- a/app/code/Magento/Sales/Setup/UpgradeData.php +++ b/app/code/Magento/Sales/Setup/UpgradeData.php @@ -1,95 +1,114 @@ salesSetupFactory = $salesSetupFactory; + $this->convertSerializedDataToJsonFactory = $convertSerializedDataToJsonFactory; $this->eavConfig = $eavConfig; } /** * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - /** @var SalesSetup $salesSetup */ + public function upgrade( + \Magento\Framework\Setup\ModuleDataSetupInterface $setup, + \Magento\Framework\Setup\ModuleContextInterface $context + ) { $salesSetup = $this->salesSetupFactory->create(['setup' => $setup]); - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $salesSetup->updateEntityType( - \Magento\Sales\Model\Order::ENTITY, - 'entity_model', - \Magento\Sales\Model\ResourceModel\Order::class - ); - $salesSetup->updateEntityType( - \Magento\Sales\Model\Order::ENTITY, - 'increment_model', - \Magento\Eav\Model\Entity\Increment\NumericValue::class - ); - $salesSetup->updateEntityType( - 'invoice', - 'entity_model', - \Magento\Sales\Model\ResourceModel\Order::class - ); - $salesSetup->updateEntityType( - 'invoice', - 'increment_model', - \Magento\Eav\Model\Entity\Increment\NumericValue::class - ); - $salesSetup->updateEntityType( - 'creditmemo', - 'entity_model', - \Magento\Sales\Model\ResourceModel\Order\Creditmemo::class - ); - $salesSetup->updateEntityType( - 'creditmemo', - 'increment_model', - \Magento\Eav\Model\Entity\Increment\NumericValue::class - ); - $salesSetup->updateEntityType( - 'shipment', - 'entity_model', - \Magento\Sales\Model\ResourceModel\Order\Shipment::class - ); - $salesSetup->updateEntityType( - 'shipment', - 'increment_model', - \Magento\Eav\Model\Entity\Increment\NumericValue::class - ); + $this->upgradeToTwoZeroOne($salesSetup); + } + if (version_compare($context->getVersion(), '2.0.5', '<')) { + $this->convertSerializedDataToJsonFactory->create(['salesSetup' => $salesSetup]) + ->convert(); } $this->eavConfig->clear(); - $setup->endSetup(); + } + + /** + * Upgrade to version 2.0.1 + * + * @param \Magento\Sales\Setup\SalesSetup $setup + * @return void + */ + private function upgradeToTwoZeroOne(\Magento\Sales\Setup\SalesSetup $setup) + { + $setup->updateEntityType( + \Magento\Sales\Model\Order::ENTITY, + 'entity_model', + \Magento\Sales\Model\ResourceModel\Order::class + ); + $setup->updateEntityType( + \Magento\Sales\Model\Order::ENTITY, + 'increment_model', + \Magento\Eav\Model\Entity\Increment\NumericValue::class + ); + $setup->updateEntityType( + 'invoice', + 'entity_model', + \Magento\Sales\Model\ResourceModel\Order::class + ); + $setup->updateEntityType( + 'invoice', + 'increment_model', + \Magento\Eav\Model\Entity\Increment\NumericValue::class + ); + $setup->updateEntityType( + 'creditmemo', + 'entity_model', + \Magento\Sales\Model\ResourceModel\Order\Creditmemo::class + ); + $setup->updateEntityType( + 'creditmemo', + 'increment_model', + \Magento\Eav\Model\Entity\Increment\NumericValue::class + ); + $setup->updateEntityType( + 'shipment', + 'entity_model', + \Magento\Sales\Model\ResourceModel\Order\Shipment::class + ); + $setup->updateEntityType( + 'shipment', + 'increment_model', + \Magento\Eav\Model\Entity\Increment\NumericValue::class + ); } } diff --git a/app/code/Magento/Sales/Setup/UpgradeSchema.php b/app/code/Magento/Sales/Setup/UpgradeSchema.php index b977cb28596ea..700da396b930d 100644 --- a/app/code/Magento/Sales/Setup/UpgradeSchema.php +++ b/app/code/Magento/Sales/Setup/UpgradeSchema.php @@ -1,6 +1,6 @@ addColumnBaseGrandTotal($installer); $this->addIndexBaseGrandTotal($installer); } + if (version_compare($context->getVersion(), '2.0.4', '<')) { + $tables = [ + 'sales_invoice_grid', + 'sales_order', + 'sales_shipment_grid', + ]; + foreach ($tables as $table) { + $salesConnection = $setup->getConnection(self::$connectionName); + $salesConnection->modifyColumn( + $installer->getTable($table, self::$connectionName), + 'customer_group_id', + ['type' => 'integer'] + ); + } + } + if (version_compare($context->getVersion(), '2.0.5', '<')) { + $connection = $installer->getConnection(self::$connectionName); + $connection->modifyColumn( + $installer->getTable('sales_order_payment', self::$connectionName), + 'cc_number_enc', + [ + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 'length' => 128 + ] + ); + } } /** diff --git a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Items/AbstractItemsTest.php b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Items/AbstractItemsTest.php index 24c1f8fd29f5e..b17cc56a5c351 100644 --- a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Items/AbstractItemsTest.php +++ b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Items/AbstractItemsTest.php @@ -1,6 +1,6 @@ model = $this->getMockBuilder(\Magento\Sales\Block\Adminhtml\Order\Create\AbstractCreate::class) + ->setMethods(['convertPrice']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->priceInfoMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceInfo\Base::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + $this->linkPriceMock = $this->getMockBuilder(\Magento\Downloadable\Pricing\Price\LinkPrice::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productMock->expects($this->any()) + ->method('getPriceInfo') + ->willReturn($this->priceInfoMock); + } + + public function testGetItemPrice() + { + $price = 5.6; + $resultPrice = 9.3; + + $this->linkPriceMock->expects($this->once()) + ->method('getValue') + ->willReturn($price); + $this->priceInfoMock->expects($this->once()) + ->method('getPrice') + ->with(FinalPrice::PRICE_CODE) + ->willReturn($this->linkPriceMock); + $this->model->expects($this->once()) + ->method('convertPrice') + ->with($price) + ->willReturn($resultPrice); + $this->assertEquals($resultPrice, $this->model->getItemPrice($this->productMock)); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Create/CustomerTest.php b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Create/CustomerTest.php index 0274c83e15abd..8bca83a1b4eb7 100644 --- a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Create/CustomerTest.php +++ b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Create/CustomerTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -37,11 +47,25 @@ protected function setUp() $this->coreRegistryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); $this->adminHelperMock = $this->getMock(\Magento\Sales\Helper\Admin::class, [], [], '', false); + $this->contextMock = $this->getMockBuilder(\Magento\Backend\Block\Template\Context::class) + ->disableOriginalConstructor() + ->setMethods(['getLocaleDate']) + ->getMock(); + + $this->localeDateMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class) + ->getMock(); + + $this->contextMock->expects($this->any())->method('getLocaleDate')->will( + $this->returnValue($this->localeDateMock) + ); + $this->commentsHistory = $this->objectManager->getObject( \Magento\Sales\Block\Adminhtml\Order\View\Tab\History::class, [ 'adminHelper' => $this->adminHelperMock, - 'registry' => $this->coreRegistryMock + 'registry' => $this->coreRegistryMock, + 'context' => $this->contextMock, + 'localeDate' => $this->localeDateMock ] ); } @@ -63,4 +87,39 @@ public function testGetItemCommentIsNotSet() $this->adminHelperMock->expects($this->never())->method('escapeHtmlWithLinks'); $this->assertEquals('', $this->commentsHistory->getItemComment($item)); } + + public function testGetItemCreatedAtDate() + { + $date = new \DateTime; + $item = ['created_at' => $date ]; + + $this->localeDateMock->expects($this->once()) + ->method('formatDateTime') + ->with($date, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::NONE) + ->willReturn('date'); + + $this->assertEquals('date', $this->commentsHistory->getItemCreatedAt($item)); + } + + public function testGetItemCreatedAtTime() + { + $date = new \DateTime; + $item = ['created_at' => $date ]; + + $this->localeDateMock->expects($this->once()) + ->method('formatDateTime') + ->with($date, \IntlDateFormatter::NONE, \IntlDateFormatter::MEDIUM) + ->willReturn('time'); + + $this->assertEquals('time', $this->commentsHistory->getItemCreatedAt($item, 'time')); + } + + public function testGetItemCreatedAtEmpty() + { + $item = ['title' => "Test" ]; + + $this->localeDateMock->expects($this->never())->method('formatDateTime'); + $this->assertEquals('', $this->commentsHistory->getItemCreatedAt($item)); + $this->assertEquals('', $this->commentsHistory->getItemCreatedAt($item, 'time')); + } } diff --git a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/Stub/OnlineMethod.php b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/Stub/OnlineMethod.php index b9b6df1f8a468..523339f38e79f 100644 --- a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/Stub/OnlineMethod.php +++ b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/View/Tab/Stub/OnlineMethod.php @@ -1,6 +1,6 @@ orderStatusCollectionFactoryMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\Status\CollectionFactory::class, + ['create'], + [], + '', + false, + false + ); + $this->configMock = $helper->getObject( + \Magento\Sales\Model\Order\Config::class, + [ + 'orderStatusCollectionFactory' => $this->orderStatusCollectionFactoryMock + ] + ); + $this->stateColumn = $helper + ->getObject( + \Magento\Sales\Block\Status\Grid\Column\State::class, + [ + 'config' => $this->configMock, + ] + ); + } + + public function testDecorateState() + { + $rowMock = $this->getMock(\Magento\Sales\Model\Order\Status::class, [], [], '', false); + $rowMock->expects($this->any())->method('getStatus')->willReturn('fraud'); + $columnMock = $this->getMock(\Magento\Backend\Block\Widget\Grid\Column::class, [], [], '', false); + $statuses = [ + new \Magento\Framework\DataObject( + [ + 'status' => 'fraud', + 'state' => 'processing', + 'label' => 'Suspected Fraud', + ] + ), + new \Magento\Framework\DataObject( + [ + 'status' => 'processing', + 'state' => 'processing', + 'label' => 'Processing', + ] + ) + ]; + $collectionMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\Status\Collection::class, + ['create', 'joinStates'], + [], + '', + false, + false + ); + $this->orderStatusCollectionFactoryMock->expects($this->once()) + ->method('create') + ->will($this->returnValue($collectionMock)); + $collectionMock->expects($this->once()) + ->method('joinStates') + ->will($this->returnValue($statuses)); + + $result = $this->stateColumn->decorateState('processing', $rowMock, $columnMock, false); + $this->assertSame('processing[processing]', $result); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php index f8c1b8d35a7b5..dcff47f54ca66 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Creditmemo/AbstractCreditmemo/EmailTest.php @@ -1,6 +1,6 @@ messageManager = $this->getMock( + \Magento\Framework\Message\Manager::class, + ['addSuccess', 'addError'], + [], + '', + false + ); + + $this->orderCollectionMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\Collection::class, + [], + [], + '', + false + ); + $this->filterMock = $this->getMock(\Magento\Ui\Component\MassAction\Filter::class, [], [], '', false); + + $this->orderCollectionFactoryMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class, + ['create'], + [], + '', + false + ); + + $this->orderCollectionFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($this->orderCollectionMock); + $this->resultRedirect = $this->getMock(\Magento\Backend\Model\View\Result\Redirect::class, [], [], '', false); + $resultRedirectFactory = $this->getMock( + \Magento\Framework\Controller\ResultFactory::class, + [], + [], + '', + false + ); + $resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirect); + $this->controller = $objectManagerHelper->getObject( + \Magento\Sales\Controller\Adminhtml\Order\Pdfinvoices::class, + [ + 'filter' => $this->filterMock, + 'resultFactory' => $resultRedirectFactory, + 'messageManager' => $this->messageManager + ] + ); + $objectManagerHelper + ->setBackwardCompatibleProperty( + $this->controller, + 'orderCollectionFactory', + $this->orderCollectionFactoryMock + ); + } + + public function testExecute() + { + $exception = new \Exception(); + $this->filterMock + ->expects($this->once()) + ->method('getCollection') + ->with($this->orderCollectionMock) + ->willThrowException($exception); + $this->messageManager->expects($this->once())->method('addError'); + + $this->resultRedirect->expects($this->once())->method('setPath')->willReturnSelf(); + $this->controller->execute($exception); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php index 387fc3b782b10..618add9d3c457 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Download/DownloadCustomOptionTest.php @@ -1,11 +1,14 @@ setMethods(['downloadFile']) ->getMock(); - $this->unserializeMock = $this->getMockBuilder(\Magento\Framework\Unserialize\Unserialize::class) + $this->serializerMock = $this->getMockBuilder(Json::class) ->disableOriginalConstructor() - ->setMethods(['unserialize']) + ->setMethods(['serialize', 'unserialize']) ->getMock(); $requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) @@ -151,7 +154,8 @@ protected function setUp() 'context' => $contextMock, 'resultForwardFactory' => $resultForwardFactoryMock, 'download' => $this->downloadMock, - 'unserialize' => $this->unserializeMock + 'unserialize' => $this->getMock(Unserialize::class, [], [], '', false), + 'serializer' => $this->serializerMock ] ) ->getMock(); @@ -197,7 +201,7 @@ public function testExecute($itemOptionValues, $productOptionValues, $noRouteOcc } else { $unserializeResult = [self::SECRET_KEY => self::SECRET_KEY]; - $this->unserializeMock->expects($this->once()) + $this->serializerMock->expects($this->once()) ->method('unserialize') ->with($itemOptionValues[self::OPTION_VALUE]) ->willReturn($unserializeResult); @@ -321,7 +325,7 @@ public function testExecuteBadSecretKey() $this->productOptionMock->expects($this->any())->method('getProductId')->willReturn(self::OPTION_PRODUCT_ID); $this->productOptionMock->expects($this->any())->method('getType')->willReturn(self::OPTION_TYPE); - $this->unserializeMock->expects($this->once()) + $this->serializerMock->expects($this->once()) ->method('unserialize') ->with(self::OPTION_VALUE) ->willReturn([self::SECRET_KEY => 'bad_test_secret_key']); diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Guest/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Guest/ViewTest.php index b119d25303348..ad5f8dcbc2305 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Guest/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Guest/ViewTest.php @@ -1,6 +1,6 @@ getMock(\Psr\Log\LoggerInterface::class); $copyMock = $this->getMock(\Magento\Framework\DataObject\Copy::class, [], [], '', false); $messageManagerMock = $this->getMock(\Magento\Framework\Message\ManagerInterface::class); - $this->formFactoryMock = $this->getMock( + $this->formFactoryMock = $this->getMock( \Magento\Customer\Model\Metadata\FormFactory::class, ['create'], [], '', false ); - $this->customerFactoryMock = $this->getMock( + $this->customerFactoryMock = $this->getMock( \Magento\Customer\Api\Data\CustomerInterfaceFactory::class, ['create'], [], @@ -122,56 +122,56 @@ protected function setUp() ->setMethods(['create']) ->getMock(); - $this->customerMapper = $this->getMockBuilder( + $this->customerMapper = $this->getMockBuilder( \Magento\Customer\Model\Customer\Mapper::class )->setMethods(['toFlatArray'])->disableOriginalConstructor()->getMock(); - $this->quoteInitializerMock = $this->getMock( + $this->quoteInitializerMock = $this->getMock( \Magento\Sales\Model\AdminOrder\Product\Quote\Initializer::class, [], [], '', false ); - $this->customerRepositoryMock = $this->getMockForAbstractClass( + $this->customerRepositoryMock = $this->getMockForAbstractClass( \Magento\Customer\Api\CustomerRepositoryInterface::class, [], '', false ); - $this->addressRepositoryMock = $this->getMockForAbstractClass( + $this->addressRepositoryMock = $this->getMockForAbstractClass( \Magento\Customer\Api\AddressRepositoryInterface::class, [], '', false ); - $this->addressFactoryMock = $this->getMock( + $this->addressFactoryMock = $this->getMock( \Magento\Customer\Api\Data\AddressInterfaceFactory::class, [], [], '', false ); - $this->groupRepositoryMock = $this->getMockForAbstractClass( + $this->groupRepositoryMock = $this->getMockForAbstractClass( \Magento\Customer\Api\GroupRepositoryInterface::class, [], '', false ); - $this->scopeConfigMock = $this->getMockForAbstractClass( + $this->scopeConfigMock = $this->getMockForAbstractClass( \Magento\Framework\App\Config\ScopeConfigInterface::class, [], '', false ); - $this->emailSenderMock = $this->getMock( + $this->emailSenderMock = $this->getMock( \Magento\Sales\Model\AdminOrder\EmailSender::class, [], [], '', false ); - $this->accountManagementMock = $this->getMockForAbstractClass( + $this->accountManagementMock = $this->getMockForAbstractClass( \Magento\Customer\Api\AccountManagementInterface::class, [], '', @@ -182,7 +182,7 @@ protected function setUp() ->getMock(); $objectManagerHelper = new ObjectManagerHelper($this); - $this->adminOrderCreate = $objectManagerHelper->getObject( + $this->adminOrderCreate = $objectManagerHelper->getObject( \Magento\Sales\Model\AdminOrder\Create::class, [ 'objectManager' => $objectManagerMock, @@ -219,7 +219,7 @@ public function testSetAccountData() $attributeMocks = []; foreach ($attributes as $attribute) { - $attributeMock = $this->getMock( + $attributeMock = $this->getMock( \Magento\Customer\Api\Data\AttributeMetadataInterface::class, [], [], @@ -232,7 +232,7 @@ public function testSetAccountData() $attributeMocks[] = $attributeMock; } - $customerGroupMock = $this->getMockForAbstractClass( + $customerGroupMock = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\GroupInterface::class, [], '', @@ -243,9 +243,11 @@ public function testSetAccountData() ); $customerGroupMock->expects($this->once())->method('getTaxClassId')->will($this->returnValue($taxClassId)); $customerFormMock = $this->getMock(\Magento\Customer\Model\Metadata\Form::class, [], [], '', false); - $customerFormMock->expects($this->any())->method('getAttributes')->will($this->returnValue($attributeMocks)); + $customerFormMock->expects($this->any()) + ->method('getAttributes') + ->will($this->returnValue([$attributeMocks[1]])); $customerFormMock->expects($this->any())->method('extractData')->will($this->returnValue([])); - $customerFormMock->expects($this->any())->method('restoreData')->will($this->returnValue([])); + $customerFormMock->expects($this->any())->method('restoreData')->will($this->returnValue(['group_id' => 1])); $customerFormMock->expects($this->any()) ->method('prepareRequest') @@ -254,7 +256,7 @@ public function testSetAccountData() $customerMock = $this->getMock(\Magento\Customer\Api\Data\CustomerInterface::class, [], [], '', false); $this->customerMapper->expects($this->atLeastOnce()) ->method('toFlatArray') - ->willReturn(['email' => 'user@example.com', 'group_id' => 1, 'gender' => 1]); + ->willReturn(['group_id' => 1]); $quoteMock = $this->getMock(\Magento\Quote\Model\Quote::class, [], [], '', false); @@ -263,7 +265,6 @@ public function testSetAccountData() ->method('addData') ->with( [ - 'customer_email' => $attributes[0][1], 'customer_group_id' => $attributes[1][1], 'customer_tax_class_id' => $taxClassId ] @@ -272,7 +273,7 @@ public function testSetAccountData() ->method('populateWithArray') ->with( $customerMock, - ['email' => 'user@example.com', 'group_id' => 1, 'gender' => 1], \Magento\Customer\Api\Data\CustomerInterface::class + ['group_id' => 1], \Magento\Customer\Api\Data\CustomerInterface::class ); $this->formFactoryMock->expects($this->any())->method('create')->will($this->returnValue($customerFormMock)); @@ -283,7 +284,7 @@ public function testSetAccountData() ->method('getById') ->will($this->returnValue($customerGroupMock)); - $this->adminOrderCreate->setAccountData([]); + $this->adminOrderCreate->setAccountData(['group_id' => 1]); } public function testUpdateQuoteItemsNotArray() @@ -350,4 +351,32 @@ public function testUpdateQuoteItemsWithConfiguredOption() $this->adminOrderCreate->setRecollect(false); $this->adminOrderCreate->updateQuoteItems($items); } + + public function testApplyCoupon() + { + $couponCode = ''; + $quoteMock = $this->getMock( + \Magento\Quote\Model\Quote::class, + ['getShippingAddress', 'setCouponCode'], + [], + '', + false + ); + $this->sessionQuoteMock->expects($this->once())->method('getQuote')->willReturn($quoteMock); + + $addressMock = $this->getMock( + \Magento\Quote\Model\Quote\Address::class, + ['setCollectShippingRates', 'setFreeShipping'], + [], + '', + false + ); + $quoteMock->expects($this->exactly(2))->method('getShippingAddress')->willReturn($addressMock); + $quoteMock->expects($this->once())->method('setCouponCode')->with($couponCode)->willReturnSelf(); + + $addressMock->expects($this->once())->method('setCollectShippingRates')->with(true)->willReturnSelf(); + $addressMock->expects($this->once())->method('setFreeShipping')->with(null)->willReturnSelf(); + + $this->adminOrderCreate->applyCoupon($couponCode); + } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php index 81cf63a466a01..a8a9722cb99a5 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/EmailSenderTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->_readerMock = $this->getMockBuilder( \Magento\Sales\Model\Config\Reader::class )->disableOriginalConstructor()->getMock(); $this->_cacheMock = $this->getMockBuilder( \Magento\Framework\App\Cache\Type\Config::class )->disableOriginalConstructor()->getMock(); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); } public function testGet() { $expected = ['someData' => ['someValue', 'someKey' => 'someValue']]; - $this->_cacheMock->expects($this->any())->method('load')->will($this->returnValue(serialize($expected))); - $configData = new \Magento\Sales\Model\Config\Data($this->_readerMock, $this->_cacheMock); + $this->_cacheMock->expects($this->once()) + ->method('load'); + + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn($expected); + + $configData = $this->objectManager->getObject( + \Magento\Sales\Model\Config\Data::class, + [ + 'reader' => $this->_readerMock, + 'cache' => $this->_cacheMock, + 'serializer' => $this->serializerMock, + ] + ); $this->assertEquals($expected, $configData->get()); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/ReaderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Config/ReaderTest.php index 5a7bd82faa723..15c437cf0b368 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Config/ReaderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Config/ReaderTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_duplicates.xml b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_duplicates.xml index 4373ddfd59b66..5deb1ee72bfd0 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_duplicates.xml +++ b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_duplicates.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_root_node.xml b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_root_node.xml index bf1a7b1b17a87..8c35a2705bd5e 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_root_node.xml +++ b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_root_node.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_scope.xml b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_scope.xml index c8c646169f09c..0f1071b627fc0 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_scope.xml +++ b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_scope.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_without_attributes.xml b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_without_attributes.xml index a69b2bf55ed8e..c8eae54ebdd0f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_without_attributes.xml +++ b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_invalid_without_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_valid.xml b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_valid.xml index c8c646169f09c..0f1071b627fc0 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_valid.xml +++ b/app/code/Magento/Sales/Test/Unit/Model/Config/_files/sales_valid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Sales/Test/Unit/Model/ConfigTest.php index 42419d62a8c15..30276afb47ce3 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/ConfigTest.php @@ -1,6 +1,6 @@ resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) @@ -131,14 +131,6 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->invoiceValidatorMock = $this->getMockBuilder(InvoiceValidatorInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class) ->disableOriginalConstructor() ->getMock(); @@ -183,22 +175,37 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); + $this->invoiceOrderValidatorMock = $this->getMockBuilder(InvoiceOrderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->errorMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class) + ->disableOriginalConstructor() + ->setMethods(['hasMessages', 'getMessages', 'addMessage']) + ->getMock(); + $this->invoiceOrder = new InvoiceOrder( $this->resourceConnectionMock, $this->orderRepositoryMock, $this->invoiceDocumentFactoryMock, - $this->invoiceValidatorMock, - $this->orderValidatorMock, $this->paymentAdapterMock, $this->orderStateResolverMock, $this->configMock, $this->invoiceRepositoryMock, + $this->invoiceOrderValidatorMock, $this->notifierInterfaceMock, $this->loggerMock ); } /** + * @param int $orderId + * @param bool $capture + * @param array $items + * @param bool $notify + * @param bool $appendComment + * @throws \Magento\Sales\Exception\CouldNotInvoiceException + * @throws \Magento\Sales\Exception\DocumentValidationException * @dataProvider dataProvider */ public function testOrderInvoice($orderId, $capture, $items, $notify, $appendComment) @@ -207,11 +214,9 @@ public function testOrderInvoice($orderId, $capture, $items, $notify, $appendCom ->method('getConnection') ->with('sales') ->willReturn($this->adapterInterface); - $this->orderRepositoryMock->expects($this->once()) ->method('get') ->willReturn($this->orderMock); - $this->invoiceDocumentFactoryMock->expects($this->once()) ->method('create') ->with( @@ -221,66 +226,62 @@ public function testOrderInvoice($orderId, $capture, $items, $notify, $appendCom ($appendComment && $notify), $this->invoiceCreationArgumentsMock )->willReturn($this->invoiceMock); - - $this->invoiceValidatorMock->expects($this->once()) - ->method('validate') - ->with($this->invoiceMock) - ->willReturn([]); - $this->orderValidatorMock->expects($this->once()) + $this->invoiceOrderValidatorMock->expects($this->once()) ->method('validate') - ->with($this->orderMock) - ->willReturn([]); - + ->with( + $this->orderMock, + $this->invoiceMock, + $capture, + $items, + $notify, + $appendComment, + $this->invoiceCommentCreationMock, + $this->invoiceCreationArgumentsMock + ) + ->willReturn($this->errorMessagesMock); + $hasMessages = false; + $this->errorMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); $this->paymentAdapterMock->expects($this->once()) ->method('pay') ->with($this->orderMock, $this->invoiceMock, $capture) ->willReturn($this->orderMock); - $this->orderStateResolverMock->expects($this->once()) ->method('getStateForOrder') ->with($this->orderMock, [OrderStateResolverInterface::IN_PROGRESS]) ->willReturn(Order::STATE_PROCESSING); - $this->orderMock->expects($this->once()) ->method('setState') ->with(Order::STATE_PROCESSING) ->willReturnSelf(); - $this->orderMock->expects($this->once()) ->method('getState') ->willReturn(Order::STATE_PROCESSING); - $this->configMock->expects($this->once()) ->method('getStateDefaultStatus') ->with(Order::STATE_PROCESSING) ->willReturn('Processing'); - $this->orderMock->expects($this->once()) ->method('setStatus') ->with('Processing') ->willReturnSelf(); - $this->invoiceMock->expects($this->once()) ->method('setState') ->with(\Magento\Sales\Model\Order\Invoice::STATE_PAID) ->willReturnSelf(); - $this->invoiceRepositoryMock->expects($this->once()) ->method('save') ->with($this->invoiceMock) ->willReturn($this->invoiceMock); - $this->orderRepositoryMock->expects($this->once()) ->method('save') ->with($this->orderMock) ->willReturn($this->orderMock); - if ($notify) { $this->notifierInterfaceMock->expects($this->once()) ->method('notify') ->with($this->orderMock, $this->invoiceMock, $this->invoiceCommentCreationMock); } - $this->invoiceMock->expects($this->once()) ->method('getEntityId') ->willReturn(2); @@ -325,14 +326,25 @@ public function testDocumentValidationException() $this->invoiceCreationArgumentsMock )->willReturn($this->invoiceMock); - $this->invoiceValidatorMock->expects($this->once()) - ->method('validate') - ->with($this->invoiceMock) - ->willReturn($errorMessages); - $this->orderValidatorMock->expects($this->once()) + $this->invoiceOrderValidatorMock->expects($this->once()) ->method('validate') - ->with($this->orderMock) - ->willReturn([]); + ->with( + $this->orderMock, + $this->invoiceMock, + $capture, + $items, + $notify, + $appendComment, + $this->invoiceCommentCreationMock, + $this->invoiceCreationArgumentsMock + ) + ->willReturn($this->errorMessagesMock); + $hasMessages = true; + + $this->errorMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $this->errorMessagesMock->expects($this->once()) + ->method('getMessages')->willReturn($errorMessages); $this->invoiceOrder->execute( $orderId, @@ -374,16 +386,25 @@ public function testCouldNotInvoiceException() $this->invoiceCreationArgumentsMock )->willReturn($this->invoiceMock); - $this->invoiceValidatorMock->expects($this->once()) - ->method('validate') - ->with($this->invoiceMock) - ->willReturn([]); - $this->orderValidatorMock->expects($this->once()) + $this->invoiceOrderValidatorMock->expects($this->once()) ->method('validate') - ->with($this->orderMock) - ->willReturn([]); - $e = new \Exception(); + ->with( + $this->orderMock, + $this->invoiceMock, + $capture, + $items, + $notify, + $appendComment, + $this->invoiceCommentCreationMock, + $this->invoiceCreationArgumentsMock + ) + ->willReturn($this->errorMessagesMock); + $hasMessages = false; + $this->errorMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + + $e = new \Exception(); $this->paymentAdapterMock->expects($this->once()) ->method('pay') ->with($this->orderMock, $this->invoiceMock, $capture) diff --git a/app/code/Magento/Sales/Test/Unit/Model/InvoiceRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/InvoiceRepositoryTest.php index 5c3d970d42f81..845c6c44fc0b2 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/InvoiceRepositoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/InvoiceRepositoryTest.php @@ -1,6 +1,6 @@ customerAddressConfigMock = $this->getMockBuilder(CustomerAddressConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->eventManagerMock = $this->getMockBuilder(EventManager::class) + ->getMockForAbstractClass(); + $this->orderAddressMock = $this->getMockBuilder(OrderAddress::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderMock = $this->getMockBuilder(Order::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerAddressBlockRendererMock = $this->getMockBuilder(CustomerAddressBlockRenderer::class) + ->getMockForAbstractClass(); + + $this->orderAddressMock->expects(static::any()) + ->method('getOrder') + ->willReturn($this->orderMock); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->orderAddressRenderer = $this->objectManagerHelper->getObject( + OrderAddressRenderer::class, + [ + 'addressConfig' => $this->customerAddressConfigMock, + 'eventManager' => $this->eventManagerMock + ] + ); + } + + public function testFormat() + { + $type = 'html'; + $formatType = new DataObject(['renderer' => $this->customerAddressBlockRendererMock]); + $addressData = ['address', 'data']; + $result = 'result string'; + + $this->setStoreExpectations(1); + $this->customerAddressConfigMock->expects(static::atLeastOnce()) + ->method('getFormatByCode') + ->with($type) + ->willReturn($formatType); + $this->eventManagerMock->expects(static::once()) + ->method('dispatch') + ->with('customer_address_format', ['type' => $formatType, 'address' => $this->orderAddressMock]); + $this->orderAddressMock->expects(static::atLeastOnce()) + ->method('getData') + ->willReturn($addressData); + $this->customerAddressBlockRendererMock->expects(static::once()) + ->method('renderArray') + ->with($addressData, null) + ->willReturn($result); + + $this->assertEquals($result, $this->orderAddressRenderer->format($this->orderAddressMock, $type)); + } + + public function testFormatNoRenderer() + { + $type = 'html'; + + $this->setStoreExpectations(1); + $this->customerAddressConfigMock->expects(static::atLeastOnce()) + ->method('getFormatByCode') + ->with($type) + ->willReturn(null); + $this->eventManagerMock->expects(static::never()) + ->method('dispatch'); + + $this->assertEquals(null, $this->orderAddressRenderer->format($this->orderAddressMock, $type)); + } + + /** + * Set expectations for store + * + * @param string|int $storeId + * @return void + */ + private function setStoreExpectations($storeId) + { + $this->orderMock->expects(static::atLeastOnce()) + ->method('getStoreId') + ->willReturn($storeId); + $this->customerAddressConfigMock->expects(static::atLeastOnce()) + ->method('setStore') + ->with($storeId) + ->willReturnSelf(); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Address/ValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Address/ValidatorTest.php index d7e341a70d7db..c95b0cdfea7b8 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Address/ValidatorTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Address/ValidatorTest.php @@ -1,6 +1,6 @@ 'canceled', 'is_default' => 1, 'visible_on_front' => 1, ] ), - new \Magento\Framework\DataObject( + new DataObject( [ 'status' => 'complete', 'is_default' => 1, 'visible_on_front' => 0, ] ), - new \Magento\Framework\DataObject( + new DataObject( [ 'status' => 'processing', 'is_default' => 1, 'visible_on_front' => 1, ] ), - new \Magento\Framework\DataObject( + new DataObject( [ 'status' => 'pending_payment', 'is_default' => 1, @@ -78,7 +79,7 @@ public function testGetInvisibleOnFrontStatuses() $expectedResult = ['complete', 'pending_payment']; $collectionMock = $this->getMock( - \Magento\Sales\Model\ResourceModel\Order\Status\Collection::class, + Collection::class, ['create', 'joinStates'], [], '', @@ -95,4 +96,134 @@ public function testGetInvisibleOnFrontStatuses() $result = $this->salesConfig->getInvisibleOnFrontStatuses(); $this->assertSame($expectedResult, $result); } + + public function testGetStateLabelByStateAndStatus() + { + $statuses = [ + new DataObject( + [ + 'status' => 'fraud', + 'state' => 'processing', + 'label' => 'Suspected Fraud', + ] + ), + new DataObject( + [ + 'status' => 'processing', + 'state' => 'processing', + 'label' => 'Processing', + ] + ) + ]; + $collectionMock = $this->getMock( + Collection::class, + ['create', 'joinStates'], + [], + '', + false, + false + ); + $this->orderStatusCollectionFactoryMock->expects($this->once()) + ->method('create') + ->will($this->returnValue($collectionMock)); + $collectionMock->expects($this->once()) + ->method('joinStates') + ->will($this->returnValue($statuses)); + $result = $this->salesConfig->getStateLabelByStateAndStatus('processing', 'fraud'); + $this->assertSame('Suspected Fraud', $result->getText()); + } + + /** + * Test get statuses + * + * @dataProvider getStatusesDataProvider + * + * @param string $state + * @param bool $joinLabels + * @param DataObject[] $collectionData + * @param array $expectedResult + */ + public function testGetStatuses($state, $joinLabels, $collectionData, $expectedResult) + { + $collectionMock = $this->getMock( + Collection::class, + ['create', 'joinStates', 'addStateFilter', 'orderByLabel'], + [], + '', + false, + false + ); + $this->orderStatusCollectionFactoryMock->expects($this->any()) + ->method('create') + ->will($this->returnValue($collectionMock)); + + $collectionMock->expects($this->once()) + ->method('addStateFilter') + ->will($this->returnSelf()); + + $collectionMock->expects($this->once()) + ->method('orderByLabel') + ->will($this->returnValue($collectionData)); + + $collectionMock->expects($this->once()) + ->method('joinStates') + ->will($this->returnValue($collectionData)); + + $result = $this->salesConfig->getStateStatuses($state, $joinLabels); + $this->assertSame($expectedResult, $result); + + // checking data cached in private property + $this->assertSame($result, $this->salesConfig->getStateStatuses($state, $joinLabels)); + } + + /** + * Data provider for testGetStatuses + * + * @return array + */ + public function getStatusesDataProvider() + { + return [ + 'processing state' => [ + 'state' => 'processing', + 'joinLabels' => false, + 'collectionData' => [ + new DataObject( + [ + 'status' => 'fraud', + 'state' => 'processing', + 'store_label' => 'Suspected Fraud', + ] + ), + new DataObject( + [ + 'status' => 'processing', + 'state' => 'processing', + 'store_label' => 'Processing', + ] + ), + ], + 'expectedResult' => [ + 0 => 'fraud', + 1 => 'processing' + ], + ], + 'pending state' => [ + 'state' => 'pending', + 'joinLabels' => true, + 'collectionData' => [ + new DataObject( + [ + 'status' => 'pending_status', + 'state' => 'pending', + 'store_label' => 'Pending label', + ] + ), + ], + 'expectedResult' => [ + 'pending_status' => 'Pending label' + ], + ], + ]; + } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Comment/ValidatorTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Comment/ValidatorTest.php index e9b02d5c5dee2..78bcc90dcab19 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Comment/ValidatorTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Comment/ValidatorTest.php @@ -1,6 +1,6 @@ orderItemRepositoryMock = $this->getMockBuilder(OrderItemRepositoryInterface::class) + ->disableOriginalConstructor() + ->setMethods(['get']) + ->getMockForAbstractClass(); + + $this->orderItemMock = $this->getMockBuilder(Item::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->entity = $this->getMockBuilder(\stdClass::class) + ->disableOriginalConstructor() + ->setMethods(['getOrderItemId', 'getQty']) + ->getMock(); + } + + /** + * @dataProvider dataProvider + */ + public function testValidateCreditMemoProductItems($orderItemId, $expectedResult, $withContext = false) + { + if ($orderItemId) { + $this->entity->expects($this->once()) + ->method('getOrderItemId') + ->willReturn($orderItemId); + + $this->orderItemRepositoryMock->expects($this->once()) + ->method('get') + ->with($orderItemId) + ->willReturn($this->orderItemMock); + } else { + $this->entity->expects($this->once()) + ->method('getOrderItemId') + ->willThrowException(new NoSuchEntityException()); + } + + $this->contexMock = null; + if ($withContext) { + $this->contexMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->entity->expects($this->once()) + ->method('getQty') + ->willReturn(11); + } + + $this->createQuantityValidator = new CreationQuantityValidator( + $this->orderItemRepositoryMock, + $this->contexMock + ); + + $this->assertEquals($expectedResult, $this->createQuantityValidator->validate($this->entity)); + } + + public function dataProvider() + { + return [ + 'testValidateCreditMemoProductItems' => [ + 1, + [__('The creditmemo contains product item that is not part of the original order.')], + ], + 'testValidateWithException' => [ + null, + [__('The creditmemo contains product item that is not part of the original order.')] + ], + 'testValidateWithContext' => [ + 1, + [__('The quantity to refund must not be greater than the unrefunded quantity.')], + true + ], + ]; + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/ItemTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/ItemTest.php index ce5797637679e..1f239f42de3bf 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/ItemTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/ItemTest.php @@ -1,6 +1,6 @@ creditmemoMock = $this->getMockBuilder(\Magento\Sales\Api\Data\CreditmemoInterface::class) ->disableOriginalConstructor() - ->setMethods(['getBaseCost']) + ->setMethods(['getBaseCost', 'setDoTransaction']) ->getMockForAbstractClass(); $this->paymentMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class) @@ -142,6 +142,7 @@ public function testExecuteWithWrongOrder() public function testExecuteOffline($amounts) { $orderId = 1; + $online = false; $this->creditmemoMock->expects($this->once()) ->method('getState') ->willReturn(Creditmemo::STATE_REFUNDED); @@ -174,8 +175,17 @@ public function testExecuteOffline($amounts) $this->orderMock->expects($this->never()) ->method('setTotalOnlineRefunded'); - $this->orderMock->expects($this->never()) - ->method('getPayment'); + $this->orderMock->expects($this->once()) + ->method('getPayment') + ->willReturn($this->paymentMock); + + $this->paymentMock->expects($this->once()) + ->method('refund') + ->with($this->creditmemoMock); + + $this->creditmemoMock->expects($this->once()) + ->method('setDoTransaction') + ->with($online); $this->eventManagerMock->expects($this->once()) ->method('dispatch') @@ -186,7 +196,7 @@ public function testExecuteOffline($amounts) $this->assertEquals( $this->orderMock, - $this->subject->execute($this->creditmemoMock, $this->orderMock, false) + $this->subject->execute($this->creditmemoMock, $this->orderMock, $online) ); } @@ -197,6 +207,7 @@ public function testExecuteOffline($amounts) public function testExecuteOnline($amounts) { $orderId = 1; + $online = true; $this->creditmemoMock->expects($this->once()) ->method('getState') ->willReturn(Creditmemo::STATE_REFUNDED); @@ -229,6 +240,10 @@ public function testExecuteOnline($amounts) $this->orderMock->expects($this->never()) ->method('setTotalOfflineRefunded'); + $this->creditmemoMock->expects($this->once()) + ->method('setDoTransaction') + ->with($online); + $this->orderMock->expects($this->once()) ->method('getPayment') ->willReturn($this->paymentMock); @@ -238,7 +253,7 @@ public function testExecuteOnline($amounts) $this->assertEquals( $this->orderMock, - $this->subject->execute($this->creditmemoMock, $this->orderMock, true) + $this->subject->execute($this->creditmemoMock, $this->orderMock, $online) ); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php new file mode 100644 index 0000000000000..294d44d5039de --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php @@ -0,0 +1,361 @@ +orderMock = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) + ->setMethods(['getStoreId']) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeMock->expects($this->any()) + ->method('getStoreId') + ->willReturn(1); + $this->orderMock->expects($this->any()) + ->method('getStore') + ->willReturn($this->storeMock); + + $this->senderMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Email\Sender::class) + ->disableOriginalConstructor() + ->setMethods(['send', 'sendCopyTo']) + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->creditmemoMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Creditmemo::class) + ->disableOriginalConstructor() + ->setMethods(['setSendEmail', 'setEmailSent']) + ->getMock(); + + $this->commentMock = $this->getMockBuilder(\Magento\Sales\Api\Data\CreditmemoCommentCreationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->commentMock->expects($this->any()) + ->method('getComment') + ->willReturn('Comment text'); + + $this->addressMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Address::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->orderMock->expects($this->any()) + ->method('getBillingAddress') + ->willReturn($this->addressMock); + $this->orderMock->expects($this->any()) + ->method('getShippingAddress') + ->willReturn($this->addressMock); + + $this->globalConfigMock = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->eventManagerMock = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->paymentInfoMock = $this->getMockBuilder(\Magento\Payment\Model\Info::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->orderMock->expects($this->any()) + ->method('getPayment') + ->willReturn($this->paymentInfoMock); + + $this->paymentHelperMock = $this->getMockBuilder(\Magento\Payment\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->paymentHelperMock->expects($this->any()) + ->method('getInfoBlockHtml') + ->with($this->paymentInfoMock, 1) + ->willReturn('Payment Info Block'); + + $this->creditmemoResourceMock = $this->getMockBuilder( + \Magento\Sales\Model\ResourceModel\Order\Creditmemo::class + )->disableOriginalConstructor() + ->getMock(); + + $this->addressRendererMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Address\Renderer::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->addressRendererMock->expects($this->any()) + ->method('format') + ->with($this->addressMock, 'html') + ->willReturn('Formatted address'); + + $this->templateContainerMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Email\Container\Template::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->identityContainerMock = $this->getMockBuilder( + \Magento\Sales\Model\Order\Email\Container\CreditmemoIdentity::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->identityContainerMock->expects($this->any()) + ->method('getStore') + ->willReturn($this->storeMock); + + $this->senderBuilderFactoryMock = $this->getMockBuilder( + \Magento\Sales\Model\Order\Email\SenderBuilderFactory::class + ) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->subject = new \Magento\Sales\Model\Order\Creditmemo\Sender\EmailSender( + $this->templateContainerMock, + $this->identityContainerMock, + $this->senderBuilderFactoryMock, + $this->loggerMock, + $this->addressRendererMock, + $this->paymentHelperMock, + $this->creditmemoResourceMock, + $this->globalConfigMock, + $this->eventManagerMock + ); + } + + /** + * @param int $configValue + * @param bool $forceSyncMode + * @param bool $isComment + * @param bool $emailSendingResult + * + * @dataProvider sendDataProvider + * + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testSend($configValue, $forceSyncMode, $isComment, $emailSendingResult) + { + $this->globalConfigMock->expects($this->once()) + ->method('getValue') + ->with('sales_email/general/async_sending') + ->willReturn($configValue); + + if (!$isComment) { + $this->commentMock = null; + } + + $this->creditmemoMock->expects($this->once()) + ->method('setSendEmail') + ->with(true); + + if (!$configValue || $forceSyncMode) { + $transport = [ + 'order' => $this->orderMock, + 'creditmemo' => $this->creditmemoMock, + 'comment' => $isComment ? 'Comment text' : '', + 'billing' => $this->addressMock, + 'payment_html' => 'Payment Info Block', + 'store' => $this->storeMock, + 'formattedShippingAddress' => 'Formatted address', + 'formattedBillingAddress' => 'Formatted address', + ]; + + $this->eventManagerMock->expects($this->once()) + ->method('dispatch') + ->with( + 'email_creditmemo_set_template_vars_before', + [ + 'sender' => $this->subject, + 'transport' => $transport, + ] + ); + + $this->templateContainerMock->expects($this->once()) + ->method('setTemplateVars') + ->with($transport); + + $this->identityContainerMock->expects($this->once()) + ->method('isEnabled') + ->willReturn($emailSendingResult); + + if ($emailSendingResult) { + $this->senderBuilderFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->senderMock); + + $this->senderMock->expects($this->once()) + ->method('send'); + + $this->senderMock->expects($this->once()) + ->method('sendCopyTo'); + + $this->creditmemoMock->expects($this->once()) + ->method('setEmailSent') + ->with(true); + + $this->creditmemoResourceMock->expects($this->once()) + ->method('saveAttribute') + ->with($this->creditmemoMock, ['send_email', 'email_sent']); + + $this->assertTrue( + $this->subject->send( + $this->orderMock, + $this->creditmemoMock, + $this->commentMock, + $forceSyncMode + ) + ); + } else { + $this->creditmemoResourceMock->expects($this->once()) + ->method('saveAttribute') + ->with($this->creditmemoMock, 'send_email'); + + $this->assertFalse( + $this->subject->send( + $this->orderMock, + $this->creditmemoMock, + $this->commentMock, + $forceSyncMode + ) + ); + } + } else { + $this->creditmemoMock->expects($this->once()) + ->method('setEmailSent') + ->with(null); + + $this->creditmemoResourceMock->expects($this->at(0)) + ->method('saveAttribute') + ->with($this->creditmemoMock, 'email_sent'); + $this->creditmemoResourceMock->expects($this->at(1)) + ->method('saveAttribute') + ->with($this->creditmemoMock, 'send_email'); + + $this->assertFalse( + $this->subject->send( + $this->orderMock, + $this->creditmemoMock, + $this->commentMock, + $forceSyncMode + ) + ); + } + } + + /** + * @return array + */ + public function sendDataProvider() + { + return [ + 'Successful sync sending with comment' => [0, false, true, true], + 'Successful sync sending without comment' => [0, false, false, true], + 'Failed sync sending with comment' => [0, false, true, false], + 'Successful forced sync sending with comment' => [1, true, true, true], + 'Async sending' => [1, false, false, false], + ]; + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/CostTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/CostTest.php index 83a3764dbf726..50d1fb6dfd417 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/CostTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/CostTest.php @@ -1,6 +1,6 @@ orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->invoiceRepositoryMock = $this->getMockBuilder(InvoiceRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->priceCurrencyMock = $this->getMockBuilder(PriceCurrencyInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->validator = new QuantityValidator( + $this->orderRepositoryMock, + $this->invoiceRepositoryMock, + $this->priceCurrencyMock + ); + } + + public function testValidateWithoutItems() + { + $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $creditmemoMock->expects($this->exactly(2))->method('getOrderId') + ->willReturn(1); + $creditmemoMock->expects($this->once())->method('getItems') + ->willReturn([]); + $orderMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $orderMock->expects($this->once())->method('getItems') + ->willReturn([]); + + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->with(1) + ->willReturn($orderMock); + $creditmemoMock->expects($this->once())->method('getGrandTotal') + ->willReturn(0); + $this->assertEquals( + [ + __('The credit memo\'s total must be positive.') + ], + $this->validator->validate($creditmemoMock) + ); + } + + public function testValidateWithoutOrder() + { + $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $creditmemoMock->expects($this->once())->method('getOrderId') + ->willReturn(null); + $creditmemoMock->expects($this->never())->method('getItems'); + $this->assertEquals( + [__('Order Id is required for creditmemo document')], + $this->validator->validate($creditmemoMock) + ); + } + + public function testValidateWithWrongItemId() + { + $orderId = 1; + $orderItemId = 1; + $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $creditmemoMock->expects($this->exactly(2))->method('getOrderId') + ->willReturn($orderId); + $creditmemoItemMock = $this->getMockBuilder( + \Magento\Sales\Api\Data\CreditmemoItemInterface::class + )->disableOriginalConstructor() + ->getMockForAbstractClass(); + $creditmemoItemMock->expects($this->once())->method('getOrderItemId') + ->willReturn($orderItemId); + $creditmemoItemSku = 'sku'; + $creditmemoItemMock->expects($this->once())->method('getSku') + ->willReturn($creditmemoItemSku); + $creditmemoMock->expects($this->exactly(1))->method('getItems') + ->willReturn([$creditmemoItemMock]); + + $orderMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $orderMock->expects($this->once())->method('getItems') + ->willReturn([]); + + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->with($orderId) + ->willReturn($orderMock); + $creditmemoMock->expects($this->once())->method('getGrandTotal') + ->willReturn(12); + + $this->assertEquals( + [ + __( + 'The creditmemo contains product SKU "%1" that is not part of the original order.', + $creditmemoItemSku + ), + __('You can\'t create a creditmemo without products.') + ], + $this->validator->validate($creditmemoMock) + ); + } + + /** + * @param int $orderId + * @param int $orderItemId + * @param int $qtyToRequest + * @param int $qtyToRefund + * @param string $sku + * @param array $expected + * @dataProvider dataProviderForValidateQty + */ + public function testValidate($orderId, $orderItemId, $qtyToRequest, $qtyToRefund, $sku, $total, array $expected) + { + $creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $creditmemoMock->expects($this->exactly(2))->method('getOrderId') + ->willReturn($orderId); + $creditmemoMock->expects($this->once())->method('getGrandTotal') + ->willReturn($total); + $creditmemoItemMock = $this->getMockBuilder( + \Magento\Sales\Api\Data\CreditmemoItemInterface::class + )->disableOriginalConstructor() + ->getMockForAbstractClass(); + $creditmemoItemMock->expects($this->exactly(2))->method('getOrderItemId') + ->willReturn($orderItemId); + $creditmemoItemMock->expects($this->never())->method('getSku') + ->willReturn($sku); + $creditmemoItemMock->expects($this->atLeastOnce())->method('getQty') + ->willReturn($qtyToRequest); + $creditmemoMock->expects($this->exactly(1))->method('getItems') + ->willReturn([$creditmemoItemMock]); + + $orderMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) + ->disableOriginalConstructor() + ->getMock(); + $orderItemMock->expects($this->exactly(2))->method('getQtyToRefund') + ->willReturn($qtyToRefund); + $creditmemoItemMock->expects($this->any())->method('getQty') + ->willReturn($qtyToRequest); + $orderMock->expects($this->once())->method('getItems') + ->willReturn([$orderItemMock]); + $orderItemMock->expects($this->once())->method('getItemId') + ->willReturn($orderItemId); + $orderItemMock->expects($this->any())->method('getSku') + ->willReturn($sku); + + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->with($orderId) + ->willReturn($orderMock); + + $this->assertEquals( + $expected, + $this->validator->validate($creditmemoMock) + ); + } + + /** + * @return array + */ + public function dataProviderForValidateQty() + { + $sku = 'sku'; + + return [ + [ + 'orderId' => 1, + 'orderItemId' => 1, + 'qtyToRequest' => 1, + 'qtyToRefund' => 1, + 'sku', + 'total' => 15, + 'expected' => [] + ], + [ + 'orderId' => 1, + 'orderItemId' => 1, + 'qtyToRequest' => 2, + 'qtyToRefund' => 1, + 'sku', + 'total' => 0, + 'expected' => [ + __( + 'The quantity to creditmemo must not be greater than the unrefunded quantity' + . ' for product SKU "%1".', + $sku + ), + __('The credit memo\'s total must be positive.') + ] + ], + ]; + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoDocumentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoDocumentFactoryTest.php new file mode 100644 index 0000000000000..2e1360cd94309 --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoDocumentFactoryTest.php @@ -0,0 +1,265 @@ +objectManager = new ObjectManager($this); + $this->creditmemoFactoryMock = $this->getMockBuilder(CreditmemoFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->commentFactoryMock = + $this->getMockBuilder('Magento\Sales\Api\Data\CreditmemoCommentInterfaceFactory') + ->setMethods(['create']) + ->getMock(); + $this->hydratorPoolMock = $this->getMockBuilder(HydratorPool::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderMock = $this->getMockBuilder(Order::class) + ->disableOriginalConstructor() + ->getMock(); + $this->invoiceMock = $this->getMockBuilder(Invoice::class) + ->disableOriginalConstructor() + ->getMock(); + $this->creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->hydratorMock = $this->getMockBuilder(HydratorInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->commentCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->commentCreationMock = $this->getMockBuilder(CreditmemoCommentCreationInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->creditmemoMock->expects($this->once()) + ->method('getEntityId') + ->willReturn(11); + + $this->commentMock = $this->getMockBuilder(CreditmemoCommentInterface::class) + ->disableOriginalConstructor() + ->setMethods( + array_merge( + get_class_methods(CreditmemoCommentInterface::class), + ['setStoreId', 'setCreditmemo'] + ) + ) + ->getMock(); + $this->factory = $this->objectManager->getObject( + CreditmemoDocumentFactory::class, + [ + 'creditmemoFactory' => $this->creditmemoFactoryMock, + 'commentFactory' => $this->commentFactoryMock, + 'hydratorPool' => $this->hydratorPoolMock, + 'orderRepository' => $this->orderRepositoryMock + ] + ); + } + + private function commonFactoryFlow() + { + $this->creditmemoItemCreationMock->expects($this->once()) + ->method('getOrderItemId') + ->willReturn(7); + $this->creditmemoItemCreationMock->expects($this->once()) + ->method('getQty') + ->willReturn(3); + $this->hydratorPoolMock->expects($this->exactly(2)) + ->method('getHydrator') + ->willReturnMap( + [ + [CreditmemoCreationArgumentsInterface::class, $this->hydratorMock], + [CreditmemoCommentCreationInterface::class, $this->hydratorMock], + ] + ); + $this->hydratorMock->expects($this->exactly(2)) + ->method('extract') + ->willReturnMap([ + [$this->commentCreationArgumentsMock, ['shipping_amount' => '20.00']], + [$this->commentCreationMock, ['comment' => 'text']] + ]); + $this->commentFactoryMock->expects($this->once()) + ->method('create') + ->with( + [ + 'data' => [ + 'comment' => 'text' + ] + ] + ) + ->willReturn($this->commentMock); + $this->creditmemoMock->expects($this->once()) + ->method('getEntityId') + ->willReturn(11); + $this->creditmemoMock->expects($this->once()) + ->method('getStoreId') + ->willReturn(1); + $this->commentMock->expects($this->once()) + ->method('setParentId') + ->with(11) + ->willReturnSelf(); + $this->commentMock->expects($this->once()) + ->method('setStoreId') + ->with(1) + ->willReturnSelf(); + $this->commentMock->expects($this->once()) + ->method('setIsCustomerNotified') + ->with(true) + ->willReturnSelf(); + $this->commentMock->expects($this->once()) + ->method('setCreditmemo') + ->with($this->creditmemoMock) + ->willReturnSelf(); + } + + public function testCreateFromOrder() + { + $this->commonFactoryFlow(); + $this->creditmemoFactoryMock->expects($this->once()) + ->method('createByOrder') + ->with( + $this->orderMock, + [ + 'shipping_amount' => '20.00', + 'qtys' => [7 => 3] + ] + ) + ->willReturn($this->creditmemoMock); + $this->factory->createFromOrder( + $this->orderMock, + [$this->creditmemoItemCreationMock], + $this->commentCreationMock, + true, + $this->commentCreationArgumentsMock + ); + } + + public function testCreateFromInvoice() + { + $this->commonFactoryFlow(); + $this->creditmemoFactoryMock->expects($this->once()) + ->method('createByInvoice') + ->with( + $this->invoiceMock, + [ + 'shipping_amount' => '20.00', + 'qtys' => [7 => 3] + ] + ) + ->willReturn($this->creditmemoMock); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + $this->invoiceMock->expects($this->once()) + ->method('setOrder') + ->with($this->orderMock) + ->willReturnSelf(); + $this->factory->createFromInvoice( + $this->invoiceMock, + [$this->creditmemoItemCreationMock], + $this->commentCreationMock, + true, + $this->commentCreationArgumentsMock + ); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoNotifierTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoNotifierTest.php index 360c47fa95635..368baa289de22 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoNotifierTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoNotifierTest.php @@ -1,6 +1,6 @@ gripPoolMock = $this->getMock(\Magento\Sales\Model\ResourceModel\GridPool::class, [], [], '', false); + $this->attributeMock = $this->getMock(\Magento\Sales\Model\ResourceModel\Attribute::class, [], [], '', false); + $this->model = new \Magento\Sales\Model\Order\Invoice\Plugin\AddressUpdate( + $this->gripPoolMock, + $this->attributeMock + ); + } + + public function testAfterProcess() + { + $billingId = 100; + $shippingId = 200; + $orderId = 50; + + $orderMock = $this->getMock( + \Magento\Sales\Model\Order::class, + ['hasInvoices', 'getBillingAddress', 'getShippingAddress', 'getInvoiceCollection', 'getId'], + [], + '', + false + ); + + $shippingMock = $this->getMock(\Magento\Sales\Model\Order\Address::class, [], [], '', false); + $shippingMock->expects($this->once())->method('getId')->willReturn($shippingId); + + $billingMock = $this->getMock(\Magento\Sales\Model\Order\Address::class, [], [], '', false); + $billingMock->expects($this->once())->method('getId')->willReturn($billingId); + + $invoiceCollectionMock = $this->getMock( + \Magento\Sales\Model\ResourceModel\Order\Invoice\Collection::class, + [], + [], + '', + false + ); + $invoiceMock = $this->getMock(\Magento\Sales\Model\Order\Invoice::class, [], [], '', false); + $invoiceCollectionMock->expects($this->once())->method('getItems')->willReturn([$invoiceMock]); + + $orderMock->expects($this->once())->method('hasInvoices')->willReturn(true); + $orderMock->expects($this->once())->method('getBillingAddress')->willReturn($billingMock); + $orderMock->expects($this->once())->method('getShippingAddress')->willReturn($shippingMock); + $orderMock->expects($this->once())->method('getInvoiceCollection')->willReturn($invoiceCollectionMock); + $orderMock->expects($this->once())->method('getId')->willReturn($orderId); + + $invoiceMock->expects($this->once())->method('getBillingAddressId')->willReturn(null); + $invoiceMock->expects($this->once())->method('getShippingAddressId')->willReturn(null); + $invoiceMock->expects($this->once())->method('setShippingAddressId')->with($shippingId)->willReturnSelf(); + $invoiceMock->expects($this->once())->method('setBillingAddressId')->with($billingId)->willReturnSelf(); + + $this->attributeMock->expects($this->once()) + ->method('saveAttribute') + ->with($invoiceMock, ['billing_address_id', 'shipping_address_id']) + ->willReturnSelf(); + + $this->gripPoolMock->expects($this->once())->method('refreshByOrderId')->with($orderId)->willReturnSelf(); + + $this->model->afterProcess( + $this->getMock(\Magento\Sales\Model\ResourceModel\Order\Handler\Address::class, [], [], '', false), + $this->getMock(\Magento\Sales\Model\ResourceModel\Order\Handler\Address::class, [], [], '', false), + $orderMock + ); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php index 3a93c591725ae..c4b1edf449fba 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php @@ -1,6 +1,6 @@ invoiceMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Invoice::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderPaymentRepositoryMock = $this->getMockBuilder( + \Magento\Sales\Api\OrderPaymentRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->paymentMock = $this->getMockBuilder(\Magento\Payment\Model\InfoInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->validator = new \Magento\Sales\Model\Order\Invoice\Validation\CanRefund( + $this->orderPaymentRepositoryMock, + $this->orderRepositoryMock + ); + } + + public function testValidateWrongInvoiceState() + { + $this->invoiceMock->expects($this->exactly(2)) + ->method('getState') + ->willReturnOnConsecutiveCalls( + \Magento\Sales\Model\Order\Invoice::STATE_OPEN, + \Magento\Sales\Model\Order\Invoice::STATE_CANCELED + ); + $this->assertEquals( + [__('We can\'t create creditmemo for the invoice.')], + $this->validator->validate($this->invoiceMock) + ); + $this->assertEquals( + [__('We can\'t create creditmemo for the invoice.')], + $this->validator->validate($this->invoiceMock) + ); + } + + public function testValidateInvoiceSumWasRefunded() + { + $this->invoiceMock->expects($this->once()) + ->method('getState') + ->willReturn(\Magento\Sales\Model\Order\Invoice::STATE_PAID); + $this->invoiceMock->expects($this->once()) + ->method('getBaseGrandTotal') + ->willReturn(1); + $this->invoiceMock->expects($this->once()) + ->method('getBaseTotalRefunded') + ->willReturn(1); + $this->assertEquals( + [__('We can\'t create creditmemo for the invoice.')], + $this->validator->validate($this->invoiceMock) + ); + } + + public function testValidate() + { + $this->invoiceMock->expects($this->once()) + ->method('getState') + ->willReturn(\Magento\Sales\Model\Order\Invoice::STATE_PAID); + $orderMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($orderMock); + $orderMock->expects($this->once()) + ->method('getPayment') + ->willReturn($this->paymentMock); + $methodInstanceMock = $this->getMockBuilder(\Magento\Payment\Model\MethodInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->paymentMock->expects($this->once()) + ->method('getMethodInstance') + ->willReturn($methodInstanceMock); + $methodInstanceMock->expects($this->atLeastOnce()) + ->method('canRefund') + ->willReturn(true); + $this->invoiceMock->expects($this->once()) + ->method('getBaseGrandTotal') + ->willReturn(1); + $this->invoiceMock->expects($this->once()) + ->method('getBaseTotalRefunded') + ->willReturn(0); + $this->assertEquals( + [], + $this->validator->validate($this->invoiceMock) + ); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceDocumentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceDocumentFactoryTest.php index d054e0803a7eb..aafafb42585c9 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceDocumentFactoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceDocumentFactoryTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->orderFactory = $this->getMock(\Magento\Sales\Model\OrderFactory::class, ['create'], [], '', false); + $this->serializerMock = $this->getMock(Json::class, [], ['unserialize'], '', false); + $arguments = [ 'orderFactory' => $this->orderFactory, + 'serializer' => $this->serializerMock ]; $this->model = $this->objectManager->getObject(\Magento\Sales\Model\Order\Item::class, $arguments); } @@ -173,4 +182,55 @@ public function testGetOriginalPrice() $this->model->setData(\Magento\Sales\Api\Data\OrderItemInterface::ORIGINAL_PRICE, $originalPrice); $this->assertEquals($originalPrice, $this->model->getOriginalPrice()); } + + /** + * Test get product options with serialization + * + * @param array|string $options + * @param array $expectedResult + * + * @dataProvider getProductOptionsDataProvider + */ + public function testGetProductOptions($options, $expectedResult) + { + if (is_string($options)) { + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->will($this->returnValue($expectedResult)); + } + $this->model->setData('product_options', $options); + $result = $this->model->getProductOptions(); + $this->assertSame($result, $expectedResult); + } + + /** + * Data provider for testGetProductOptions + * + * @return array + */ + public function getProductOptionsDataProvider() + { + return [ + 'array' => [ + 'options' => [ + 'option1' => 'option 1 value', + 'option2' => 'option 2 value', + ], + 'expectedResult' => [ + 'option1' => 'option 1 value', + 'option2' => 'option 2 value', + ] + ], + 'serialized' => [ + 'options' => json_encode([ + 'option1' => 'option 1 value', + 'option2' => 'option 2 value', + ]), + 'expectedResult' => [ + 'option1' => 'option 1 value', + 'option2' => 'option 2 value', + ] + ] + ]; + } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Payment/InfoTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Payment/InfoTest.php index 9bb5e47db947c..c303e510c5bcb 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Payment/InfoTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Payment/InfoTest.php @@ -1,6 +1,6 @@ orderStateResolverMock = $this->getMockBuilder(Order\OrderStateResolverInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); $this->payment = $this->initPayment(); + $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $helper->setBackwardCompatibleProperty($this->payment, 'orderStateResolver', $this->orderStateResolverMock); $this->payment->setMethod('any'); $this->payment->setOrder($this->orderMock); $this->transactionId = self::TRANSACTION_ID; @@ -1465,6 +1481,9 @@ public function testRefund() $this->creditMemoMock->expects(static::once()) ->method('getInvoice') ->willReturn($this->invoiceMock); + $this->creditMemoMock->expects(static::once()) + ->method('getOrder') + ->willReturn($this->orderMock); $captureTranId = self::TRANSACTION_ID . '-' . Transaction::TYPE_CAPTURE; $captureTransaction = $this->getMockBuilder(Transaction::class) @@ -1499,7 +1518,10 @@ public function testRefund() $status = 'status'; $message = 'We refunded ' . $amount . ' online. Transaction ID: "' . $refundTranId . '"'; - $this->mockGetDefaultStatus(Order::STATE_PROCESSING, $status); + $this->orderStateResolverMock->expects($this->once())->method('getStateForOrder') + ->with($this->orderMock) + ->willReturn(Order::STATE_CLOSED); + $this->mockGetDefaultStatus(Order::STATE_CLOSED, $status); $this->assertOrderUpdated(Order::STATE_PROCESSING, $status, $message); static::assertSame($this->payment, $this->payment->refund($this->creditMemoMock)); @@ -1526,7 +1548,7 @@ public function testIsCaptureFinal() $partialAmount = 12.00; $this->orderMock->expects(static::exactly(2)) - ->method('getTotalDue') + ->method('getBaseTotalDue') ->willReturn($amount); static::assertFalse($this->payment->isCaptureFinal($partialAmount)); diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/AbstractTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/AbstractTest.php index 4041fd922f364..3e489db90ccb4 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/AbstractTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/AbstractTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_one.xml b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_one.xml index 47770047afe68..a997e39a092ff 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_one.xml +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_one.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_two.xml b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_two.xml index ca7c178febe64..8d132d09f8dd6 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_two.xml +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/Config/_files/pdf_two.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/ConfigTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/ConfigTest.php index 44148e20d5fcc..c00d7017e63a3 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/ConfigTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Pdf/ConfigTest.php @@ -1,6 +1,6 @@ logger = $this->getMock(\Psr\Log\LoggerInterface::class); $this->salesConfig = $this->getMock(\Magento\Sales\Model\Config::class, [], [], '', false); $this->orderTotalFactory = $this->getMock(\Magento\Sales\Model\Order\TotalFactory::class, [], [], '', false); + $this->serializer = $this->getMockForAbstractClass(SerializerInterface::class); $objectManager = new ObjectManager($this); $this->object = $objectManager->getObject( @@ -39,6 +44,7 @@ protected function setUp() 'logger' => $this->logger, 'salesConfig' => $this->salesConfig, 'orderTotalFactory' => $this->orderTotalFactory, + 'serializer' => $this->serializer, ] ); } @@ -59,8 +65,14 @@ public function testGetTotalModels() ->with(\Magento\Sales\Model\Order\Total\AbstractTotal::class) ->will($this->returnValue($total)); + $sortedCodes = ['other_code', 'some_code']; + $serializedCodes = '["other_code", "some_code"]'; + $this->serializer->expects($this->once()) + ->method('serialize') + ->with($sortedCodes) + ->willReturn($serializedCodes); $this->configCacheType->expects($this->once())->method('save') - ->with('a:2:{i:0;s:10:"other_code";i:1;s:9:"some_code";}', 'sorted_collectors'); + ->with($serializedCodes, 'sorted_collectors'); $this->assertSame( ['other_code' => $total, 'some_code' => $total], @@ -106,8 +118,14 @@ public function testGetTotalUnserializeCachedCollectorCodes() ->with(\Magento\Sales\Model\Order\Total\AbstractTotal::class) ->will($this->returnValue($total)); + $sortedCodes = ['other_code', 'some_code']; + $serializedCodes = '["other_code", "some_code"]'; $this->configCacheType->expects($this->once())->method('load')->with('sorted_collectors') - ->will($this->returnValue('a:2:{i:0;s:10:"other_code";i:1;s:9:"some_code";}')); + ->will($this->returnValue($serializedCodes)); + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($serializedCodes) + ->willReturn($sortedCodes); $this->configCacheType->expects($this->never())->method('save'); $this->assertSame( diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanInvoiceTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanInvoiceTest.php index dd76bc1e52586..158b743392d3b 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanInvoiceTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanInvoiceTest.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->orderMock = $this->getMockBuilder(\Magento\Sales\Api\Data\OrderInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getStatus', 'getItems']) + ->getMockForAbstractClass(); + + $this->priceCurrencyMock = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->priceCurrencyMock->expects($this->any()) + ->method('round') + ->willReturnArgument(0); + $this->model = new \Magento\Sales\Model\Order\Validation\CanRefund( + $this->priceCurrencyMock + ); + } + + /** + * @param string $state + * + * @dataProvider canCreditmemoWrongStateDataProvider + */ + public function testCanCreditmemoWrongState($state) + { + $this->orderMock->expects($this->any()) + ->method('getState') + ->willReturn($state); + $this->orderMock->expects($this->once()) + ->method('getStatus') + ->willReturn('status'); + $this->orderMock->expects($this->never()) + ->method('getTotalPaid') + ->willReturn(15); + $this->orderMock->expects($this->never()) + ->method('getTotalRefunded') + ->willReturn(14); + $this->assertEquals( + [__('A creditmemo can not be created when an order has a status of %1', 'status')], + $this->model->validate($this->orderMock) + ); + } + + /** + * Data provider for testCanCreditmemoWrongState + * @return array + */ + public function canCreditmemoWrongStateDataProvider() + { + return [ + [Order::STATE_PAYMENT_REVIEW], + [Order::STATE_HOLDED], + [Order::STATE_CANCELED], + [Order::STATE_CLOSED], + ]; + } + + public function testCanCreditmemoNoMoney() + { + $this->orderMock->expects($this->any()) + ->method('getState') + ->willReturn(Order::STATE_PROCESSING); + $this->orderMock->expects($this->once()) + ->method('getTotalPaid') + ->willReturn(15); + $this->orderMock->expects($this->once()) + ->method('getTotalRefunded') + ->willReturn(15); + $this->assertEquals( + [ + __('The order does not allow a creditmemo to be created.') + ], + $this->model->validate($this->orderMock) + ); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanShipTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanShipTest.php index 11d99fbb9cced..107a67e1a2bc8 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanShipTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Validation/CanShipTest.php @@ -1,6 +1,6 @@ assertEquals($collectionMock, $this->model->getList($searchCriteriaMock)); } + + public function testSave() + { + $mapperMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order::class) + ->disableOriginalConstructor() + ->getMock(); + $orderEntity = $this->getMock(\Magento\Sales\Model\Order::class, [], [], '', false); + $extensionAttributes = $this->getMock( + \Magento\Sales\Api\Data\OrderExtension::class, + ['getShippingAssignments'], + [], + '', + false + ); + $shippingAssignment = $this->getMockBuilder(\Magento\Sales\Model\Order\ShippingAssignment::class) + ->disableOriginalConstructor() + ->setMethods(['getShipping']) + ->getMock(); + $shippingMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipping::class) + ->disableOriginalConstructor() + ->setMethods(['getAddress', 'getMethod']) + ->getMock(); + $orderEntity->expects($this->once())->method('getExtensionAttributes')->willReturn($extensionAttributes); + $orderEntity->expects($this->once())->method('getIsNotVirtual')->willReturn(true); + $extensionAttributes + ->expects($this->any()) + ->method('getShippingAssignments') + ->willReturn([$shippingAssignment]); + $shippingAssignment->expects($this->once())->method('getShipping')->willReturn($shippingMock); + $shippingMock->expects($this->once())->method('getAddress'); + $shippingMock->expects($this->once())->method('getMethod'); + $this->metadata->expects($this->once())->method('getMapper')->willReturn($mapperMock); + $mapperMock->expects($this->once())->method('save'); + $orderEntity->expects($this->any())->method('getEntityId')->willReturn(1); + $this->model->save($orderEntity); + } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index 9ed76a9bce6e0..fccaa6e0a78d4 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -1,6 +1,6 @@ resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->invoiceRepositoryMock = $this->getMockBuilder(InvoiceRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->creditmemoDocumentFactoryMock = $this->getMockBuilder(CreditmemoDocumentFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->refundInvoiceValidatorMock = $this->getMockBuilder(RefundInvoiceInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->configMock = $this->getMockBuilder(OrderConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->creditmemoRepositoryMock = $this->getMockBuilder(CreditmemoRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->notifierMock = $this->getMockBuilder(NotifierInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->creditmemoCommentCreationMock = $this->getMockBuilder(CreditmemoCommentCreationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->orderMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->invoiceMock = $this->getMockBuilder(InvoiceInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->adapterInterface = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->validationMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class) + ->disableOriginalConstructor() + ->setMethods(['hasMessages', 'getMessages', 'addMessage']) + ->getMock(); + + $this->refundInvoice = new RefundInvoice( + $this->resourceConnectionMock, + $this->orderStateResolverMock, + $this->orderRepositoryMock, + $this->invoiceRepositoryMock, + $this->refundInvoiceValidatorMock, + $this->creditmemoRepositoryMock, + $this->paymentAdapterMock, + $this->creditmemoDocumentFactoryMock, + $this->notifierMock, + $this->configMock, + $this->loggerMock + ); + } + + /** + * @param int $invoiceId + * @param bool $isOnline + * @param array $items + * @param bool $notify + * @param bool $appendComment + * @throws \Magento\Sales\Exception\CouldNotRefundException + * @throws \Magento\Sales\Exception\DocumentValidationException + * @dataProvider dataProvider + */ + public function testOrderCreditmemo($invoiceId, $isOnline, $items, $notify, $appendComment) + { + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->with('sales') + ->willReturn($this->adapterInterface); + $this->invoiceRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->invoiceMock); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + $this->creditmemoDocumentFactoryMock->expects($this->once()) + ->method('createFromInvoice') + ->with( + $this->invoiceMock, + $items, + $this->creditmemoCommentCreationMock, + ($appendComment && $notify), + $this->creditmemoCreationArgumentsMock + )->willReturn($this->creditmemoMock); + $this->refundInvoiceValidatorMock->expects($this->once()) + ->method('validate') + ->with( + $this->invoiceMock, + $this->orderMock, + $this->creditmemoMock, + $items, + $isOnline, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = false; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $this->paymentAdapterMock->expects($this->once()) + ->method('refund') + ->with($this->creditmemoMock, $this->orderMock) + ->willReturn($this->orderMock); + $this->orderStateResolverMock->expects($this->once()) + ->method('getStateForOrder') + ->with($this->orderMock, []) + ->willReturn(Order::STATE_CLOSED); + $this->orderMock->expects($this->once()) + ->method('setState') + ->with(Order::STATE_CLOSED) + ->willReturnSelf(); + $this->orderMock->expects($this->once()) + ->method('getState') + ->willReturn(Order::STATE_CLOSED); + $this->configMock->expects($this->once()) + ->method('getStateDefaultStatus') + ->with(Order::STATE_CLOSED) + ->willReturn('Closed'); + $this->orderMock->expects($this->once()) + ->method('setStatus') + ->with('Closed') + ->willReturnSelf(); + $this->creditmemoMock->expects($this->once()) + ->method('setState') + ->with(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED) + ->willReturnSelf(); + $this->creditmemoRepositoryMock->expects($this->once()) + ->method('save') + ->with($this->creditmemoMock) + ->willReturn($this->creditmemoMock); + $this->orderRepositoryMock->expects($this->once()) + ->method('save') + ->with($this->orderMock) + ->willReturn($this->orderMock); + if ($notify) { + $this->notifierMock->expects($this->once()) + ->method('notify') + ->with($this->orderMock, $this->creditmemoMock, $this->creditmemoCommentCreationMock); + } + $this->creditmemoMock->expects($this->once()) + ->method('getEntityId') + ->willReturn(2); + + $this->assertEquals( + 2, + $this->refundInvoice->execute( + $invoiceId, + $items, + true, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ); + } + + /** + * @expectedException \Magento\Sales\Api\Exception\DocumentValidationExceptionInterface + */ + public function testDocumentValidationException() + { + $invoiceId = 1; + $items = [1 => $this->creditmemoItemCreationMock]; + $notify = true; + $appendComment = true; + $isOnline = false; + $errorMessages = ['error1', 'error2']; + + $this->invoiceRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->invoiceMock); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + + $this->creditmemoDocumentFactoryMock->expects($this->once()) + ->method('createFromInvoice') + ->with( + $this->invoiceMock, + $items, + $this->creditmemoCommentCreationMock, + ($appendComment && $notify), + $this->creditmemoCreationArgumentsMock + )->willReturn($this->creditmemoMock); + + $this->refundInvoiceValidatorMock->expects($this->once()) + ->method('validate') + ->with( + $this->invoiceMock, + $this->orderMock, + $this->creditmemoMock, + $items, + $isOnline, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = true; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $this->validationMessagesMock->expects($this->once()) + ->method('getMessages')->willReturn($errorMessages); + + $this->assertEquals( + $errorMessages, + $this->refundInvoice->execute( + $invoiceId, + $items, + false, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ); + } + + /** + * @expectedException \Magento\Sales\Api\Exception\CouldNotRefundExceptionInterface + */ + public function testCouldNotCreditmemoException() + { + $invoiceId = 1; + $items = [1 => $this->creditmemoItemCreationMock]; + $notify = true; + $appendComment = true; + $isOnline = false; + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->with('sales') + ->willReturn($this->adapterInterface); + + $this->invoiceRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->invoiceMock); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + + $this->creditmemoDocumentFactoryMock->expects($this->once()) + ->method('createFromInvoice') + ->with( + $this->invoiceMock, + $items, + $this->creditmemoCommentCreationMock, + ($appendComment && $notify), + $this->creditmemoCreationArgumentsMock + )->willReturn($this->creditmemoMock); + + $this->refundInvoiceValidatorMock->expects($this->once()) + ->method('validate') + ->with( + $this->invoiceMock, + $this->orderMock, + $this->creditmemoMock, + $items, + $isOnline, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = false; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $e = new \Exception(); + + $this->paymentAdapterMock->expects($this->once()) + ->method('refund') + ->with($this->creditmemoMock, $this->orderMock) + ->willThrowException($e); + + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with($e); + + $this->adapterInterface->expects($this->once()) + ->method('rollBack'); + + $this->refundInvoice->execute( + $invoiceId, + $items, + false, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ); + } + + public function dataProvider() + { + $creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + return [ + 'TestWithNotifyTrue' => [1, true, [1 => $creditmemoItemCreationMock], true, true], + 'TestWithNotifyFalse' => [1, true, [1 => $creditmemoItemCreationMock], false, true], + ]; + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php new file mode 100644 index 0000000000000..21c96f5a68adb --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php @@ -0,0 +1,417 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->creditmemoDocumentFactoryMock = $this->getMockBuilder(CreditmemoDocumentFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->refundOrderValidatorMock = $this->getMockBuilder(RefundOrderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->paymentAdapterMock = $this->getMockBuilder(PaymentAdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->configMock = $this->getMockBuilder(OrderConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->creditmemoRepositoryMock = $this->getMockBuilder(CreditmemoRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->notifierMock = $this->getMockBuilder(NotifierInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->creditmemoCommentCreationMock = $this->getMockBuilder(CreditmemoCommentCreationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->creditmemoCreationArgumentsMock = $this->getMockBuilder(CreditmemoCreationArgumentsInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->orderMock = $this->getMockBuilder(OrderInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->creditmemoMock = $this->getMockBuilder(CreditmemoInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->adapterInterface = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->creditmemoItemCreationMock = $this->getMockBuilder(CreditmemoItemCreationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->validationMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class) + ->disableOriginalConstructor() + ->setMethods(['hasMessages', 'getMessages', 'addMessage']) + ->getMock(); + + $this->refundOrder = new RefundOrder( + $this->resourceConnectionMock, + $this->orderStateResolverMock, + $this->orderRepositoryMock, + $this->creditmemoRepositoryMock, + $this->paymentAdapterMock, + $this->creditmemoDocumentFactoryMock, + $this->refundOrderValidatorMock, + $this->notifierMock, + $this->configMock, + $this->loggerMock + ); + } + + /** + * @param int $orderId + * @param bool $notify + * @param bool $appendComment + * @throws \Magento\Sales\Exception\CouldNotRefundException + * @throws \Magento\Sales\Exception\DocumentValidationException + * @dataProvider dataProvider + */ + public function testOrderCreditmemo($orderId, $notify, $appendComment) + { + $items = [$this->creditmemoItemCreationMock]; + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->with('sales') + ->willReturn($this->adapterInterface); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + $this->creditmemoDocumentFactoryMock->expects($this->once()) + ->method('createFromOrder') + ->with( + $this->orderMock, + $items, + $this->creditmemoCommentCreationMock, + ($appendComment && $notify), + $this->creditmemoCreationArgumentsMock + )->willReturn($this->creditmemoMock); + $this->refundOrderValidatorMock->expects($this->once()) + ->method('validate') + ->with( + $this->orderMock, + $this->creditmemoMock, + $items, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = false; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $this->paymentAdapterMock->expects($this->once()) + ->method('refund') + ->with($this->creditmemoMock, $this->orderMock) + ->willReturn($this->orderMock); + $this->orderStateResolverMock->expects($this->once()) + ->method('getStateForOrder') + ->with($this->orderMock, []) + ->willReturn(Order::STATE_CLOSED); + $this->orderMock->expects($this->once()) + ->method('setState') + ->with(Order::STATE_CLOSED) + ->willReturnSelf(); + $this->orderMock->expects($this->once()) + ->method('getState') + ->willReturn(Order::STATE_CLOSED); + $this->configMock->expects($this->once()) + ->method('getStateDefaultStatus') + ->with(Order::STATE_CLOSED) + ->willReturn('Closed'); + $this->orderMock->expects($this->once()) + ->method('setStatus') + ->with('Closed') + ->willReturnSelf(); + $this->creditmemoMock->expects($this->once()) + ->method('setState') + ->with(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED) + ->willReturnSelf(); + $this->creditmemoRepositoryMock->expects($this->once()) + ->method('save') + ->with($this->creditmemoMock) + ->willReturn($this->creditmemoMock); + $this->orderRepositoryMock->expects($this->once()) + ->method('save') + ->with($this->orderMock) + ->willReturn($this->orderMock); + if ($notify) { + $this->notifierMock->expects($this->once()) + ->method('notify') + ->with($this->orderMock, $this->creditmemoMock, $this->creditmemoCommentCreationMock); + } + $this->creditmemoMock->expects($this->once()) + ->method('getEntityId') + ->willReturn(2); + + $this->assertEquals( + 2, + $this->refundOrder->execute( + $orderId, + $items, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ); + } + + /** + * @expectedException \Magento\Sales\Api\Exception\DocumentValidationExceptionInterface + */ + public function testDocumentValidationException() + { + $orderId = 1; + $items = [$this->creditmemoItemCreationMock]; + $notify = true; + $appendComment = true; + $errorMessages = ['error1', 'error2']; + + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + + $this->creditmemoDocumentFactoryMock->expects($this->once()) + ->method('createFromOrder') + ->with( + $this->orderMock, + $items, + $this->creditmemoCommentCreationMock, + ($appendComment && $notify), + $this->creditmemoCreationArgumentsMock + )->willReturn($this->creditmemoMock); + + $this->refundOrderValidatorMock->expects($this->once()) + ->method('validate') + ->with( + $this->orderMock, + $this->creditmemoMock, + $items, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = true; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $this->validationMessagesMock->expects($this->once()) + ->method('getMessages')->willReturn($errorMessages); + + $this->assertEquals( + $errorMessages, + $this->refundOrder->execute( + $orderId, + $items, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ); + } + + /** + * @expectedException \Magento\Sales\Api\Exception\CouldNotRefundExceptionInterface + */ + public function testCouldNotCreditmemoException() + { + $orderId = 1; + $items = [$this->creditmemoItemCreationMock]; + $notify = true; + $appendComment = true; + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->with('sales') + ->willReturn($this->adapterInterface); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->orderMock); + $this->creditmemoDocumentFactoryMock->expects($this->once()) + ->method('createFromOrder') + ->with( + $this->orderMock, + $items, + $this->creditmemoCommentCreationMock, + ($appendComment && $notify), + $this->creditmemoCreationArgumentsMock + )->willReturn($this->creditmemoMock); + $this->refundOrderValidatorMock->expects($this->once()) + ->method('validate') + ->with( + $this->orderMock, + $this->creditmemoMock, + $items, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = false; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $e = new \Exception(); + $this->paymentAdapterMock->expects($this->once()) + ->method('refund') + ->with($this->creditmemoMock, $this->orderMock) + ->willThrowException($e); + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with($e); + $this->adapterInterface->expects($this->once()) + ->method('rollBack'); + + $this->refundOrder->execute( + $orderId, + $items, + $notify, + $appendComment, + $this->creditmemoCommentCreationMock, + $this->creditmemoCreationArgumentsMock + ); + } + + public function dataProvider() + { + return [ + 'TestWithNotifyTrue' => [1, true, true], + 'TestWithNotifyFalse' => [1, false, true], + ]; + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/AttributeTest.php b/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/AttributeTest.php index ff2e492df8d09..e5fde8fdae414 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/AttributeTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/AttributeTest.php @@ -1,6 +1,6 @@ resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) ->disableOriginalConstructor() ->getMock(); - $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->shipmentDocumentFactoryMock = $this->getMockBuilder(ShipmentDocumentFactory::class) ->disableOriginalConstructor() ->getMock(); - - $this->shipmentValidatorMock = $this->getMockBuilder(ShipmentValidatorInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->orderValidatorMock = $this->getMockBuilder(OrderValidatorInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->orderRegistrarMock = $this->getMockBuilder(OrderRegistrarInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->orderStateResolverMock = $this->getMockBuilder(OrderStateResolverInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->configMock = $this->getMockBuilder(OrderConfig::class) ->disableOriginalConstructor() ->getMock(); - $this->shipmentRepositoryMock = $this->getMockBuilder(ShipmentRepositoryInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->notifierInterfaceMock = $this->getMockBuilder(NotifierInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->shipmentCommentCreationMock = $this->getMockBuilder(ShipmentCommentCreationInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->shipmentCreationArgumentsMock = $this->getMockBuilder(ShipmentCreationArgumentsInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->orderMock = $this->getMockBuilder(OrderInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->shipmentMock = $this->getMockBuilder(ShipmentInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->packageMock = $this->getMockBuilder(ShipmentPackageInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->trackMock = $this->getMockBuilder(ShipmentTrackCreationInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->adapterMock = $this->getMockBuilder(AdapterInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - + $this->shipOrderValidatorMock = $this->getMockBuilder(ShipOrderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->validationMessagesMock = $this->getMockBuilder(ValidatorResultInterface::class) + ->disableOriginalConstructor() + ->setMethods(['hasMessages', 'getMessages', 'addMessage']) + ->getMock(); $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $helper->getObject( @@ -209,20 +192,25 @@ protected function setUp() [ 'resourceConnection' => $this->resourceConnectionMock, 'orderRepository' => $this->orderRepositoryMock, - 'shipmentRepository' => $this->shipmentRepositoryMock, 'shipmentDocumentFactory' => $this->shipmentDocumentFactoryMock, - 'shipmentValidator' => $this->shipmentValidatorMock, - 'orderValidator' => $this->orderValidatorMock, 'orderStateResolver' => $this->orderStateResolverMock, - 'orderRegistrar' => $this->orderRegistrarMock, - 'notifierInterface' => $this->notifierInterfaceMock, 'config' => $this->configMock, - 'logger' => $this->loggerMock + 'shipmentRepository' => $this->shipmentRepositoryMock, + 'shipOrderValidator' => $this->shipOrderValidatorMock, + 'notifierInterface' => $this->notifierInterfaceMock, + 'logger' => $this->loggerMock, + 'orderRegistrar' => $this->orderRegistrarMock ] ); } /** + * @param int $orderId + * @param array $items + * @param bool $notify + * @param bool $appendComment + * @throws \Magento\Sales\Exception\CouldNotShipException + * @throws \Magento\Sales\Exception\DocumentValidationException * @dataProvider dataProvider */ public function testExecute($orderId, $items, $notify, $appendComment) @@ -231,11 +219,9 @@ public function testExecute($orderId, $items, $notify, $appendComment) ->method('getConnection') ->with('sales') ->willReturn($this->adapterMock); - $this->orderRepositoryMock->expects($this->once()) ->method('get') ->willReturn($this->orderMock); - $this->shipmentDocumentFactoryMock->expects($this->once()) ->method('create') ->with( @@ -247,65 +233,61 @@ public function testExecute($orderId, $items, $notify, $appendComment) [$this->packageMock], $this->shipmentCreationArgumentsMock )->willReturn($this->shipmentMock); - - $this->shipmentValidatorMock->expects($this->once()) + $this->shipOrderValidatorMock->expects($this->once()) ->method('validate') - ->with($this->shipmentMock) - ->willReturn([]); - $this->orderValidatorMock->expects($this->once()) - ->method('validate') - ->with($this->orderMock) - ->willReturn([]); - + ->with( + $this->orderMock, + $this->shipmentMock, + $items, + $notify, + $appendComment, + $this->shipmentCommentCreationMock, + [$this->trackMock], + [$this->packageMock] + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = false; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); $this->orderRegistrarMock->expects($this->once()) ->method('register') ->with($this->orderMock, $this->shipmentMock) ->willReturn($this->orderMock); - $this->orderStateResolverMock->expects($this->once()) ->method('getStateForOrder') ->with($this->orderMock, [OrderStateResolverInterface::IN_PROGRESS]) ->willReturn(Order::STATE_PROCESSING); - $this->orderMock->expects($this->once()) ->method('setState') ->with(Order::STATE_PROCESSING) ->willReturnSelf(); - $this->orderMock->expects($this->once()) ->method('getState') ->willReturn(Order::STATE_PROCESSING); - $this->configMock->expects($this->once()) ->method('getStateDefaultStatus') ->with(Order::STATE_PROCESSING) ->willReturn('Processing'); - $this->orderMock->expects($this->once()) ->method('setStatus') ->with('Processing') ->willReturnSelf(); - $this->shipmentRepositoryMock->expects($this->once()) ->method('save') ->with($this->shipmentMock) ->willReturn($this->shipmentMock); - $this->orderRepositoryMock->expects($this->once()) ->method('save') ->with($this->orderMock) ->willReturn($this->orderMock); - if ($notify) { $this->notifierInterfaceMock->expects($this->once()) ->method('notify') ->with($this->orderMock, $this->shipmentMock, $this->shipmentCommentCreationMock); } - $this->shipmentMock->expects($this->once()) ->method('getEntityId') ->willReturn(2); - $this->assertEquals( 2, $this->model->execute( @@ -348,14 +330,24 @@ public function testDocumentValidationException() $this->shipmentCreationArgumentsMock )->willReturn($this->shipmentMock); - $this->shipmentValidatorMock->expects($this->once()) + $this->shipOrderValidatorMock->expects($this->once()) ->method('validate') - ->with($this->shipmentMock) - ->willReturn($errorMessages); - $this->orderValidatorMock->expects($this->once()) - ->method('validate') - ->with($this->orderMock) - ->willReturn([]); + ->with( + $this->orderMock, + $this->shipmentMock, + $items, + $notify, + $appendComment, + $this->shipmentCommentCreationMock, + [$this->trackMock], + [$this->packageMock] + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = true; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $this->validationMessagesMock->expects($this->once()) + ->method('getMessages')->willReturn($errorMessages); $this->model->execute( $orderId, @@ -372,9 +364,12 @@ public function testDocumentValidationException() /** * @expectedException \Magento\Sales\Api\Exception\CouldNotShipExceptionInterface */ - public function testCouldNotInvoiceException() + public function testCouldNotShipException() { $orderId = 1; + $items = [1 => 2]; + $notify = true; + $appendComment = true; $this->resourceConnectionMock->expects($this->once()) ->method('getConnection') ->with('sales') @@ -387,33 +382,53 @@ public function testCouldNotInvoiceException() $this->shipmentDocumentFactoryMock->expects($this->once()) ->method('create') ->with( - $this->orderMock + $this->orderMock, + $items, + [$this->trackMock], + $this->shipmentCommentCreationMock, + ($appendComment && $notify), + [$this->packageMock], + $this->shipmentCreationArgumentsMock )->willReturn($this->shipmentMock); - - $this->shipmentValidatorMock->expects($this->once()) + $this->shipOrderValidatorMock->expects($this->once()) ->method('validate') - ->with($this->shipmentMock) - ->willReturn([]); - $this->orderValidatorMock->expects($this->once()) - ->method('validate') - ->with($this->orderMock) - ->willReturn([]); - $e = new \Exception(); + ->with( + $this->orderMock, + $this->shipmentMock, + $items, + $notify, + $appendComment, + $this->shipmentCommentCreationMock, + [$this->trackMock], + [$this->packageMock] + ) + ->willReturn($this->validationMessagesMock); + $hasMessages = false; + $this->validationMessagesMock->expects($this->once()) + ->method('hasMessages')->willReturn($hasMessages); + $exception = new \Exception(); $this->orderRegistrarMock->expects($this->once()) ->method('register') ->with($this->orderMock, $this->shipmentMock) - ->willThrowException($e); + ->willThrowException($exception); $this->loggerMock->expects($this->once()) ->method('critical') - ->with($e); + ->with($exception); $this->adapterMock->expects($this->once()) ->method('rollBack'); $this->model->execute( - $orderId + $orderId, + $items, + $notify, + $appendComment, + $this->shipmentCommentCreationMock, + [$this->trackMock], + [$this->packageMock], + $this->shipmentCreationArgumentsMock ); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Status/ListStatusTest.php b/app/code/Magento/Sales/Test/Unit/Model/Status/ListStatusTest.php index bd0d2848c3838..2b8349801975b 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Status/ListStatusTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Status/ListStatusTest.php @@ -1,6 +1,6 @@ serializeMock = $this->getMock(Serialize::class, ['unserialize'], [], '', false); + $this->serializeMock->expects($this->any()) + ->method('unserialize') + ->will( + $this->returnCallback( + function ($value) { + return unserialize($value); + } + ) + ); + $this->jsonMock = $this->getMock(Json::class, ['serialize'], [], '', false); + $this->jsonMock->expects($this->any()) + ->method('serialize') + ->will( + $this->returnCallback( + function ($value) { + return json_encode($value); + } + ) + ); + + $this->model = new \Magento\Sales\Setup\SerializedDataConverter($this->serializeMock, $this->jsonMock); + + } + + /** + * @param string $serialized + * @param string $expectedJson + * + * @dataProvider convertDataProvider + */ + public function testConvert($serialized, $expectedJson) + { + $this->assertEquals($expectedJson, $this->model->convert($serialized)); + } + + /** + * Data provider for convert method test + * + * Slashes in PHP string are implicitly escaped so they MUST be escaped manually to correspond real expected data + * + * @return array + */ + public function convertDataProvider() + { + // @codingStandardsIgnoreStart + return [ + 'dataset_1' => [ + 'serialized' => 'a:2:{s:15:"info_buyRequest";a:6:{s:4:"uenc";s:52:"aHR0cDovL20yLmxvYy9zaW1wbGUuaHRtbD9vcHRpb25zPWNhcnQ,";s:7:"product";s:1:"1";s:28:"selected_configurable_option";s:0:"";s:15:"related_product";s:0:"";s:7:"options";a:3:{i:1;s:4:"test";i:3;s:1:"2";i:2;a:9:{s:4:"type";s:10:"image/jpeg";s:5:"title";s:7:"476.jpg";s:10:"quote_path";s:61:"custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:10:"order_path";s:61:"custom_options/order/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:8:"fullpath";s:89:"C:/www/magento/ce/pub/media/custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:4:"size";s:6:"122340";s:5:"width";i:666;s:6:"height";i:940;s:10:"secret_key";s:20:"bc61f16f0cc3a8c5abd7";}}s:3:"qty";s:1:"1";}s:7:"options";a:3:{i:0;a:7:{s:5:"label";s:11:"testoption1";s:5:"value";s:4:"test";s:11:"print_value";s:4:"test";s:9:"option_id";s:1:"1";s:11:"option_type";s:5:"field";s:12:"option_value";s:4:"test";s:11:"custom_view";b:0;}i:1;a:7:{s:5:"label";s:11:"testoption2";s:5:"value";s:132:"476.jpg 666 x 940 px.";s:11:"print_value";s:21:"476.jpg 666 x 940 px.";s:9:"option_id";s:1:"2";s:11:"option_type";s:4:"file";s:12:"option_value";s:600:"a:10:{s:4:"type";s:10:"image/jpeg";s:5:"title";s:7:"476.jpg";s:10:"quote_path";s:61:"custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:10:"order_path";s:61:"custom_options/order/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:8:"fullpath";s:89:"C:/www/magento/ce/pub/media/custom_options/quote/4/7/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg";s:4:"size";s:6:"122340";s:5:"width";i:666;s:6:"height";i:940;s:10:"secret_key";s:20:"bc61f16f0cc3a8c5abd7";s:3:"url";a:2:{s:5:"route";s:35:"sales/download/downloadCustomOption";s:6:"params";a:2:{s:2:"id";s:1:"9";s:3:"key";s:20:"bc61f16f0cc3a8c5abd7";}}}";s:11:"custom_view";b:1;}i:2;a:7:{s:5:"label";s:8:"testopt3";s:5:"value";s:3:"222";s:11:"print_value";s:3:"222";s:9:"option_id";s:1:"3";s:11:"option_type";s:9:"drop_down";s:12:"option_value";s:1:"2";s:11:"custom_view";b:0;}}}', + 'expectedJson' => '{"info_buyRequest":{"uenc":"aHR0cDovL20yLmxvYy9zaW1wbGUuaHRtbD9vcHRpb25zPWNhcnQ,","product":"1","selected_configurable_option":"","related_product":"","options":{"1":"test","3":"2","2":{"type":"image\/jpeg","title":"476.jpg","quote_path":"custom_options\/quote\/4\/7\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg","order_path":"custom_options\/order\/4\/7\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg","fullpath":"C:\/www\/magento\/ce\/pub\/media\/custom_options\/quote\/4\/7\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg","size":"122340","width":666,"height":940,"secret_key":"bc61f16f0cc3a8c5abd7"}},"qty":"1"},"options":[{"label":"testoption1","value":"test","print_value":"test","option_id":"1","option_type":"field","option_value":"test","custom_view":false},{"label":"testoption2","value":"476.jpg<\/a> 666 x 940 px.","print_value":"476.jpg 666 x 940 px.","option_id":"2","option_type":"file","option_value":"{\"type\":\"image\\\\\/jpeg\",\"title\":\"476.jpg\",\"quote_path\":\"custom_options\\\\\/quote\\\\\/4\\\\\/7\\\\\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg\",\"order_path\":\"custom_options\\\\\/order\\\\\/4\\\\\/7\\\\\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg\",\"fullpath\":\"C:\\\\\/www\\\\\/magento\\\\\/ce\\\\\/pub\\\\\/media\\\\\/custom_options\\\\\/quote\\\\\/4\\\\\/7\\\\\/bc61f16f0cc3a8c5abd7ebbaad4cc139.jpg\",\"size\":\"122340\",\"width\":666,\"height\":940,\"secret_key\":\"bc61f16f0cc3a8c5abd7\",\"url\":{\"route\":\"sales\\\\\/download\\\\\/downloadCustomOption\",\"params\":{\"id\":\"9\",\"key\":\"bc61f16f0cc3a8c5abd7\"}}}","custom_view":true},{"label":"testopt3","value":"222","print_value":"222","option_id":"3","option_type":"drop_down","option_value":"2","custom_view":false}]}', + ], + 'dataset_2' => [ + 'serialized' => 'a:2:{s:15:"info_buyRequest";a:6:{s:4:"uenc";s:36:"aHR0cDovL20yLmxvYy9idW5kbGUuaHRtbA,,";s:7:"product";s:1:"4";s:28:"selected_configurable_option";s:0:"";s:15:"related_product";s:0:"";s:13:"bundle_option";a:2:{i:1;s:1:"1";i:2;s:1:"2";}s:3:"qty";s:1:"3";}s:27:"bundle_selection_attributes";s:97:"a:4:{s:5:"price";d:100;s:3:"qty";d:1;s:12:"option_label";s:8:"option 1";s:9:"option_id";s:1:"1";}";}', + 'expectedJson' => '{"info_buyRequest":{"uenc":"aHR0cDovL20yLmxvYy9idW5kbGUuaHRtbA,,","product":"4","selected_configurable_option":"","related_product":"","bundle_option":{"1":"1","2":"2"},"qty":"3"},"bundle_selection_attributes":"{\"price\":100,\"qty\":1,\"option_label\":\"option 1\",\"option_id\":\"1\"}"}', + ], + ]; + // @codingStandardsIgnoreEnd + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Ui/Component/DataProvider/DocumentTest.php b/app/code/Magento/Sales/Test/Unit/Ui/Component/DataProvider/DocumentTest.php index 5528999d1adb7..e6b4856f89cc5 100644 --- a/app/code/Magento/Sales/Test/Unit/Ui/Component/DataProvider/DocumentTest.php +++ b/app/code/Magento/Sales/Test/Unit/Ui/Component/DataProvider/DocumentTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Sales/etc/adminhtml/di.xml b/app/code/Magento/Sales/etc/adminhtml/di.xml index d15c01b5f9a7b..5beb8de6d04c9 100644 --- a/app/code/Magento/Sales/etc/adminhtml/di.xml +++ b/app/code/Magento/Sales/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/adminhtml/events.xml b/app/code/Magento/Sales/etc/adminhtml/events.xml index 1cb9401671de1..0249dce1e4d03 100644 --- a/app/code/Magento/Sales/etc/adminhtml/events.xml +++ b/app/code/Magento/Sales/etc/adminhtml/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/adminhtml/menu.xml b/app/code/Magento/Sales/etc/adminhtml/menu.xml index cca6e1d07305c..5ad5e0887fb41 100644 --- a/app/code/Magento/Sales/etc/adminhtml/menu.xml +++ b/app/code/Magento/Sales/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/adminhtml/routes.xml b/app/code/Magento/Sales/etc/adminhtml/routes.xml index 2f63f7c4c37c3..df9b84e61606d 100644 --- a/app/code/Magento/Sales/etc/adminhtml/routes.xml +++ b/app/code/Magento/Sales/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/adminhtml/system.xml b/app/code/Magento/Sales/etc/adminhtml/system.xml index 114349ed77696..7056c41ecb81a 100644 --- a/app/code/Magento/Sales/etc/adminhtml/system.xml +++ b/app/code/Magento/Sales/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/catalog_attributes.xml b/app/code/Magento/Sales/etc/catalog_attributes.xml index 50bf8636cfd3f..3fef995ae1b0a 100644 --- a/app/code/Magento/Sales/etc/catalog_attributes.xml +++ b/app/code/Magento/Sales/etc/catalog_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/config.xml b/app/code/Magento/Sales/etc/config.xml index 4d94cec460eee..3961f19f2cf60 100644 --- a/app/code/Magento/Sales/etc/config.xml +++ b/app/code/Magento/Sales/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/crontab.xml b/app/code/Magento/Sales/etc/crontab.xml index dfc5c955e3712..ec87dbc21f3df 100644 --- a/app/code/Magento/Sales/etc/crontab.xml +++ b/app/code/Magento/Sales/etc/crontab.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml index dfdb0f6a261c5..88e72e2b8a374 100644 --- a/app/code/Magento/Sales/etc/di.xml +++ b/app/code/Magento/Sales/etc/di.xml @@ -1,7 +1,7 @@ @@ -47,6 +47,8 @@ + + @@ -55,6 +57,7 @@ + @@ -100,6 +103,16 @@ + + + + + + + + + + @@ -926,6 +939,13 @@ + + + + Magento\Sales\Model\Order\Creditmemo\Sender\EmailSender + + + @@ -933,4 +953,21 @@ + + + + + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + + + diff --git a/app/code/Magento/Sales/etc/email_templates.xml b/app/code/Magento/Sales/etc/email_templates.xml index 28ef57751b2d0..52127bf90f5ad 100644 --- a/app/code/Magento/Sales/etc/email_templates.xml +++ b/app/code/Magento/Sales/etc/email_templates.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/events.xml b/app/code/Magento/Sales/etc/events.xml index be9fcb6656a6d..464f5a615b84f 100644 --- a/app/code/Magento/Sales/etc/events.xml +++ b/app/code/Magento/Sales/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/extension_attributes.xml b/app/code/Magento/Sales/etc/extension_attributes.xml index 1c8f75ca28b72..8c43f2665ebdb 100644 --- a/app/code/Magento/Sales/etc/extension_attributes.xml +++ b/app/code/Magento/Sales/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/fieldset.xml b/app/code/Magento/Sales/etc/fieldset.xml index d02b099208a21..563ab2ab6032f 100644 --- a/app/code/Magento/Sales/etc/fieldset.xml +++ b/app/code/Magento/Sales/etc/fieldset.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/frontend/di.xml b/app/code/Magento/Sales/etc/frontend/di.xml index 08c466c5ad9c3..a01b6f759eb6a 100644 --- a/app/code/Magento/Sales/etc/frontend/di.xml +++ b/app/code/Magento/Sales/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/frontend/events.xml b/app/code/Magento/Sales/etc/frontend/events.xml index 33be4fdd72212..e790d069bed46 100644 --- a/app/code/Magento/Sales/etc/frontend/events.xml +++ b/app/code/Magento/Sales/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/frontend/page_types.xml b/app/code/Magento/Sales/etc/frontend/page_types.xml index d8069d7714fa6..ceecbd9a86c7b 100644 --- a/app/code/Magento/Sales/etc/frontend/page_types.xml +++ b/app/code/Magento/Sales/etc/frontend/page_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/frontend/routes.xml b/app/code/Magento/Sales/etc/frontend/routes.xml index 0024f73961581..5e626205b4a50 100644 --- a/app/code/Magento/Sales/etc/frontend/routes.xml +++ b/app/code/Magento/Sales/etc/frontend/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/frontend/sections.xml b/app/code/Magento/Sales/etc/frontend/sections.xml index 950655ce89679..acb884723b4cb 100644 --- a/app/code/Magento/Sales/etc/frontend/sections.xml +++ b/app/code/Magento/Sales/etc/frontend/sections.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/module.xml b/app/code/Magento/Sales/etc/module.xml index 88d6e25d31fb6..4dedf44353077 100644 --- a/app/code/Magento/Sales/etc/module.xml +++ b/app/code/Magento/Sales/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Sales/etc/pdf.xml b/app/code/Magento/Sales/etc/pdf.xml index 566afd7db68e9..47042e6ebd418 100644 --- a/app/code/Magento/Sales/etc/pdf.xml +++ b/app/code/Magento/Sales/etc/pdf.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/pdf.xsd b/app/code/Magento/Sales/etc/pdf.xsd index 67828e47564b8..57b532ad3a2ee 100644 --- a/app/code/Magento/Sales/etc/pdf.xsd +++ b/app/code/Magento/Sales/etc/pdf.xsd @@ -3,7 +3,7 @@ /** * XSD for an XML, composed as result of merging all config files with PDF settings * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/app/code/Magento/Sales/etc/pdf_file.xsd b/app/code/Magento/Sales/etc/pdf_file.xsd index 2acddbb8fa5ab..29df3f46d2c39 100644 --- a/app/code/Magento/Sales/etc/pdf_file.xsd +++ b/app/code/Magento/Sales/etc/pdf_file.xsd @@ -3,7 +3,7 @@ /** * XSD for an individual file with PDF settings * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/app/code/Magento/Sales/etc/resources.xml b/app/code/Magento/Sales/etc/resources.xml index f967588fbeef0..9c7afa995c348 100644 --- a/app/code/Magento/Sales/etc/resources.xml +++ b/app/code/Magento/Sales/etc/resources.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/sales.xml b/app/code/Magento/Sales/etc/sales.xml index 070a6069f0bca..589e5d64861f7 100644 --- a/app/code/Magento/Sales/etc/sales.xml +++ b/app/code/Magento/Sales/etc/sales.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/sales.xsd b/app/code/Magento/Sales/etc/sales.xsd index 678bd9cc698fd..6d62b3fb1ef0d 100644 --- a/app/code/Magento/Sales/etc/sales.xsd +++ b/app/code/Magento/Sales/etc/sales.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/webapi.xml b/app/code/Magento/Sales/etc/webapi.xml index 4c7fe03a201f8..85c2182c1f511 100644 --- a/app/code/Magento/Sales/etc/webapi.xml +++ b/app/code/Magento/Sales/etc/webapi.xml @@ -1,7 +1,7 @@ @@ -133,6 +133,12 @@ + + + + + + @@ -181,6 +187,12 @@ + + + + + + diff --git a/app/code/Magento/Sales/etc/webapi_rest/di.xml b/app/code/Magento/Sales/etc/webapi_rest/di.xml index 259d71e138084..9d6766fadcc07 100644 --- a/app/code/Magento/Sales/etc/webapi_rest/di.xml +++ b/app/code/Magento/Sales/etc/webapi_rest/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/webapi_rest/events.xml b/app/code/Magento/Sales/etc/webapi_rest/events.xml index 33be4fdd72212..e790d069bed46 100644 --- a/app/code/Magento/Sales/etc/webapi_rest/events.xml +++ b/app/code/Magento/Sales/etc/webapi_rest/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/webapi_soap/di.xml b/app/code/Magento/Sales/etc/webapi_soap/di.xml index 259d71e138084..9d6766fadcc07 100644 --- a/app/code/Magento/Sales/etc/webapi_soap/di.xml +++ b/app/code/Magento/Sales/etc/webapi_soap/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/webapi_soap/events.xml b/app/code/Magento/Sales/etc/webapi_soap/events.xml index 33be4fdd72212..e790d069bed46 100644 --- a/app/code/Magento/Sales/etc/webapi_soap/events.xml +++ b/app/code/Magento/Sales/etc/webapi_soap/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/etc/widget.xml b/app/code/Magento/Sales/etc/widget.xml index 5a0c9da1a6b92..73a651a1c4539 100644 --- a/app/code/Magento/Sales/etc/widget.xml +++ b/app/code/Magento/Sales/etc/widget.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/registration.php b/app/code/Magento/Sales/registration.php index 18521d9d29c0a..3dab7bf893ed5 100644 --- a/app/code/Magento/Sales/registration.php +++ b/app/code/Magento/Sales/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportcsv.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportcsv.xml index 0198d1717068d..f8004598ad930 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportcsv.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportcsv.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportexcel.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportexcel.xml index 0198d1717068d..f8004598ad930 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportexcel.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_exportexcel.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_grid.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_grid.xml index eca54fd66217f..051bfadf72f76 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_index.xml index 82764c908d0de..dabfb299f3bd1 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_item_price.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_item_price.xml index cecddf978e3f5..ca4ffb0e720f4 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_item_price.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_creditmemo_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportcsv.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportcsv.xml index 08e368f49a833..187ed6b707155 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportcsv.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportcsv.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportexcel.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportexcel.xml index 08e368f49a833..187ed6b707155 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportexcel.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_exportexcel.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_grid.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_grid.xml index 9104253b9ff7c..7a1b43178d486 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_index.xml index 38e690b74b60e..0598a9f9be6d5 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_item_price.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_item_price.xml index 6b242baa1fca1..9f3e89df13f12 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_item_price.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_invoice_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_addcomment.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_addcomment.xml index f61cafa6c5b8a..3ea719f1d21de 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_addcomment.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_addcomment.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_address.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_address.xml index 6f3ebefc38bbc..b499db59189df 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_address.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_address.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml index 73add56e7e697..7a28dc1e2b823 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml index b2e779e330fe0..f6a1e61c2b8d0 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml @@ -1,7 +1,7 @@ @@ -16,7 +16,7 @@ - order-header + order-header diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_item_price.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_item_price.xml index 7eb0e126ba7b2..6c662939e1ae3 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_item_price.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_address.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_address.xml index 855d6d1dd9994..28ace5252607a 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_address.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_address.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml index 580f93a346855..2da51a9c68c80 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_billing_method.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_comment.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_comment.xml index 7f719f923b8ee..118fc08e664df 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_comment.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_comment.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_customer_grid.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_customer_grid.xml index ff7c957bbde36..6672710be8d36 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_customer_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_customer_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_data.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_data.xml index e0922b7fffb3b..79bff3ecfb55d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_data.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_data.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_form_account.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_form_account.xml index 847e707a8197e..2a0c005ef6e17 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_form_account.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_form_account.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_giftmessage.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_giftmessage.xml index dd79b30c10024..135c315c63667 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_giftmessage.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_giftmessage.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_header.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_header.xml index 48073267bd34a..9e4568cb1e7ab 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_header.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_header.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_items.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_items.xml index 36404770b08bc..5250aa47dca8d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_items.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_items.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_json.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_json.xml index cdef2f8a40e65..09ba1234e7767 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_json.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_json.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_message.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_message.xml index f2b5fa8abaf53..604bc8531e503 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_message.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_message.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_newsletter.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_newsletter.xml index 6d8fd66979714..c2afe642cf7c4 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_newsletter.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_newsletter.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_plain.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_plain.xml index f8a716806e13a..6c6a785f8963b 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_plain.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_plain.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search.xml index 0c055ee6db8dc..d175c7b5978e5 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search_grid.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search_grid.xml index e6cf5833df018..d004d626a8743 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_search_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_address.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_address.xml index 9c5a69c52f816..3afc09e1af0cd 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_address.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_address.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_method.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_method.xml index 17e1db8d9772e..eef5cdbaf741b 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_method.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_shipping_method.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar.xml index 306e329c5a614..bce15a03ee4ec 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_cart.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_cart.xml index 4ad6791352934..65ca72856c0bc 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_cart.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_cart.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_compared.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_compared.xml index 2922829e24943..b6a9abc2df8dd 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_compared.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_compared.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pcompared.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pcompared.xml index 54c0125e72da6..7c53428ba9e4b 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pcompared.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pcompared.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pviewed.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pviewed.xml index f1a4f4ff64ac7..d930927729bbc 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pviewed.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_pviewed.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_reorder.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_reorder.xml index f05223234ab55..a0cd430b0b5bd 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_reorder.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_reorder.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_viewed.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_viewed.xml index cc75faf56118f..7a113b2383963 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_viewed.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_viewed.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_wishlist.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_wishlist.xml index 4c5f859d622f5..7c1050d4be458 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_wishlist.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_sidebar_wishlist.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_totals.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_totals.xml index 93944b08f50c2..f1ff1815664f3 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_totals.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_load_block_totals.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_addcomment.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_addcomment.xml index 1e72bedebbd16..b98446dae0658 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_addcomment.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_addcomment.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml index 13ec422655160..9400b29f7ff0d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml index 2ca1a3aa5beb8..d108cacfd39b8 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml index 291e8c06036e3..23bc6a4124e6b 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml index a6ee27119d04b..c4c16653b8282 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemos.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemos.xml index 57d4a2a33902e..9a46191f05269 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemos.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemos.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_edit_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_edit_index.xml index 07994fedd2ca7..e1d61e0c61471 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_edit_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_edit_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportcsv.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportcsv.xml index 6354cc30659b7..fd80e3995d851 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportcsv.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportcsv.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportexcel.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportexcel.xml index 6354cc30659b7..fd80e3995d851 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportexcel.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_exportexcel.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_grid.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_grid.xml index f7a86f08cf675..1c67e0692bfbb 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_index.xml index c3eec0aaa9196..2ff2fe88f8d5c 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_addcomment.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_addcomment.xml index a375ea42bc2b6..d4b08f2ea7f0d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_addcomment.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_addcomment.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml index de8d290b5763f..efba38d3ccb6e 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml index 895d5b4abf01e..783b3e674babc 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml index 11ef1a132f19d..5fcd72d1c4cd0 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml index be427caed410c..f9b115c8d3b73 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoices.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoices.xml index dd1615f344ce7..da479bafef791 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoices.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoices.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_item_price.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_item_price.xml index 67a4b0af3115a..68bc52fe2205e 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_item_price.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml index efddae8969734..de4ef7c222ef7 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipments.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipments.xml index 4c2c4793c81bd..b58bd5970471f 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipments.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipments.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_assign.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_assign.xml index 5bef1d6ae043e..7038803db29ae 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_assign.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_assign.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_edit.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_edit.xml index a83805367ce60..7ca0c87b41a4a 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_edit.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml index f3c7408bb6c2b..f1744a3bceed5 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml @@ -1,7 +1,7 @@ @@ -15,7 +15,7 @@ Magento\Sales\Model\ResourceModel\Status\Collection state desc - 0 + 1 diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_new.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_new.xml index 1d7441c1994b2..40d8d19e1c1d2 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_new.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions.xml index 10686926f9e08..4857eb26f6bfe 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions_grid_block.xml index 0e47a4e165be7..42cd58e6b956d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_transactions_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml index 28d8fee45cd42..feb536d18a75e 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_view.xml @@ -1,7 +1,7 @@ @@ -23,6 +23,7 @@ + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportcsv.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportcsv.xml index 376d64327f078..b3c090f2eaf5d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportcsv.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportcsv.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportexcel.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportexcel.xml index 376d64327f078..b3c090f2eaf5d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportexcel.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_exportexcel.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_index.xml index 1f48680439183..8183382c1b6c6 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_shipment_index.xml @@ -1,7 +1,7 @@ @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml index 5c4254b66ebcb..98aa355da793b 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_transaction_child_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid.xml index eda1fe96f8bda..3e66985f7d6c5 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid_block.xml index 269651ef3b2fe..dfa2566ae02ab 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_index.xml index 1bc6165f61a39..7de682f5a70ef 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_view.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_view.xml index ec1719d8ecea1..868f1260f7d84 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_view.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_transactions_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Sales/view/adminhtml/requirejs-config.js b/app/code/Magento/Sales/view/adminhtml/requirejs-config.js index 56b989f47f874..6ecf955f48c96 100644 --- a/app/code/Magento/Sales/view/adminhtml/requirejs-config.js +++ b/app/code/Magento/Sales/view/adminhtml/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -9,4 +9,4 @@ var config = { orderEditDialog: 'Magento_Sales/order/edit/message' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Sales/view/adminhtml/templates/items/column/name.phtml b/app/code/Magento/Sales/view/adminhtml/templates/items/column/name.phtml index 2cb1b3076789c..c3235d31318cc 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/items/column/name.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/items/column/name.phtml @@ -1,6 +1,6 @@ - diff --git a/app/code/Magento/Swatches/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml b/app/code/Magento/Swatches/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml index ad17bc1cb5c5d..0f9b16f95c674 100644 --- a/app/code/Magento/Swatches/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml +++ b/app/code/Magento/Swatches/view/adminhtml/templates/catalog/product/edit/attribute/steps/attributes_values.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml b/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml index d976296315566..54de75697a85d 100644 --- a/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml +++ b/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css b/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css index f52668f65f4dc..5bdb5d1b65428 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css +++ b/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js b/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js index 165a8cf8e1eda..bda847bf837a4 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js index 17f52b5d5f68f..4ea9bc01f89ae 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/product-attributes.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/text.js b/app/code/Magento/Swatches/view/adminhtml/web/js/text.js index ac7d7ab642c6e..eb0618701350e 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/text.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/text.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/type-change.js b/app/code/Magento/Swatches/view/adminhtml/web/js/type-change.js index c2f95f85b311d..adf30c500dadc 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/type-change.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/type-change.js @@ -1,9 +1,10 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ require([ - 'jquery' + 'jquery', + 'mage/translate' ], function ($) { 'use strict'; diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/visual.js b/app/code/Magento/Swatches/view/adminhtml/web/js/visual.js index e8291d810d567..e769989497baf 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/js/visual.js +++ b/app/code/Magento/Swatches/view/adminhtml/web/js/visual.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html b/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html index fc20cfd77ca01..6351283b4bcce 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html +++ b/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml b/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml index 3b17bac8e1540..c8d243a3af960 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml b/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml index 6ba9c47382f75..c5f6df9eb11f0 100755 --- a/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalog_product_view_type_configurable.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml new file mode 100644 index 0000000000000..c8d243a3af960 --- /dev/null +++ b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml index 3b17bac8e1540..c8d243a3af960 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml b/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml new file mode 100644 index 0000000000000..eb157e3443d55 --- /dev/null +++ b/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml b/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml index 9b77cab3a1dcb..175d63bde3bc5 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml index 19b4002efb2a7..1a352d7d85019 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/layered/renderer.phtml @@ -1,6 +1,6 @@ getSwatchData(); ?>
    + attribute-code="" + attribute-id="">
    $label): ?> - +
    getSwatchPath('swatch_image', $swatchData['swatches'][$option]['value']); ?>
    diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml index 19419d4c0a7ee..dbed0abbc8ff2 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/view/renderer.phtml @@ -1,6 +1,6 @@ getJsonSwatchConfig(); ?>, "mediaCallback": "getMediaCallback() ?>", - "onlyMainImg": getVar('change_only_base_image', - 'Magento_Swatches') ?: 'false'; ?> + "gallerySwitchStrategy": "getVar('gallery_switch_strategy', + 'Magento_ConfigurableProduct') ?: 'replace'; ?>" } } } diff --git a/app/code/Magento/Swatches/view/frontend/web/css/swatches.css b/app/code/Magento/Swatches/view/frontend/web/css/swatches.css index 8204fc7fc8f63..a054cecd5c2b8 100644 --- a/app/code/Magento/Swatches/view/frontend/web/css/swatches.css +++ b/app/code/Magento/Swatches/view/frontend/web/css/swatches.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -210,6 +210,10 @@ padding: 0 !important; } +.swatch-option-link-layered:focus > div { + box-shadow: 0 0 3px 1px #68a8e0; +} + .swatch-option-tooltip-layered { width: 140px; position: absolute; @@ -276,3 +280,9 @@ .swatch-option-loading { content: url("../images/loader-2.gif"); } + +.swatch-input { + left: -1000px; + position: absolute; + visibility: hidden; +} diff --git a/app/code/Magento/Swatches/view/frontend/web/js/catalog-add-to-cart.js b/app/code/Magento/Swatches/view/frontend/web/js/catalog-add-to-cart.js new file mode 100644 index 0000000000000..0e0c94b4ad62c --- /dev/null +++ b/app/code/Magento/Swatches/view/frontend/web/js/catalog-add-to-cart.js @@ -0,0 +1,17 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +require([ + 'jquery' +], function ($) { + 'use strict'; + + $('body').on('catalogCategoryAddToCartRedirect', function (event, data) { + $(data.form).find('[name*="super"]').each(function (index, item) { + var $item = $(item); + + data.redirectParameters.push($item.attr('data-attr-name') + '=' + $item.val()); + }); + }); +}); diff --git a/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js b/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js new file mode 100644 index 0000000000000..6467c6276da58 --- /dev/null +++ b/app/code/Magento/Swatches/view/frontend/web/js/configurable-customer-data.js @@ -0,0 +1,28 @@ +require([ + 'jquery', + 'Magento_ConfigurableProduct/js/options-updater' +], function ($, Updater) { + 'use strict'; + + var selectors = { + formSelector: '#product_addtocart_form', + swatchSelector: '.swatch-opt' + }, + swatchWidgetName = 'mageSwatchRenderer', + widgetInitEvent = 'swatch.initialized', + + /** + * Sets all configurable swatch attribute's selected values + */ + updateSwatchOptions = function () { + var swatchWidget = $(selectors.swatchSelector).data(swatchWidgetName); + + if (!swatchWidget || !swatchWidget._EmulateSelectedByAttributeId) { + return; + } + swatchWidget._EmulateSelectedByAttributeId(this.productOptions); + }, + updater = new Updater(widgetInitEvent, updateSwatchOptions); + + updater.listen(); +}); diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js index dfd4b2bb2da0f..ed0933c77e897 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js @@ -1,16 +1,65 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ 'jquery', 'underscore', + 'mage/template', + 'mage/smart-keyboard-handler', + 'mage/translate', + 'priceUtils', 'jquery/ui', - 'jquery/jquery.parsequery' -], function ($, _) { + 'jquery/jquery.parsequery', + 'mage/validation/validation' +], function ($, _, mageTemplate, keyboardHandler, $t, priceUtils) { 'use strict'; + /** + * Extend form validation to support swatch accessibility + */ + $.widget('mage.validation', $.mage.validation, { + /** + * Handle form with swatches validation. Focus on first invalid swatch block. + * + * @param {jQuery.Event} event + * @param {Object} validation + */ + listenFormValidateHandler: function (event, validation) { + var swatchWrapper, firstActive, swatches, swatch, successList, errorList, firstSwatch; + + this._superApply(arguments); + + swatchWrapper = '.swatch-attribute-options'; + swatches = $(event.target).find(swatchWrapper); + + if (!swatches.length) { + return; + } + + swatch = '.swatch-attribute'; + firstActive = $(validation.errorList[0].element || []); + successList = validation.successList; + errorList = validation.errorList; + firstSwatch = $(firstActive).parent(swatch).find(swatchWrapper); + + keyboardHandler.focus(swatches); + + $.each(successList, function (index, item) { + $(item).parent(swatch).find(swatchWrapper).attr('aria-invalid', false); + }); + + $.each(errorList, function (index, item) { + $(item.element).parent(swatch).find(swatchWrapper).attr('aria-invalid', true); + }); + + if (firstSwatch.length) { + $(firstSwatch).focus(); + } + } + }); + /** * Render tooltips by attributes (only to up). * Required element attributes: @@ -117,6 +166,7 @@ define([ $element.hide(); clearTimeout(timer); }); + $(document).on('tap', function () { $element.hide(); clearTimeout(timer); @@ -169,6 +219,9 @@ define([ //selector of product images gallery wrapper mediaGallerySelector: '[data-gallery-role=gallery-placeholder]', + // selector of category product tile wrapper + selectorProductTile: '.product-item', + // number of controls to show (false or zero = show all) numberToShow: false, @@ -178,6 +231,9 @@ define([ // enable label for control enableControlLabel: true, + // control label id + controlLabelId: '', + // text for more button moreButtonText: 'More', @@ -190,8 +246,27 @@ define([ // Cache for BaseProduct images. Needed when option unset mediaGalleryInitial: [{}], - // - onlyMainImg: false + /** + * Defines the mechanism of how images of a gallery should be + * updated when user switches between configurations of a product. + * + * As for now value of this option can be either 'replace' or 'prepend'. + * + * @type {String} + */ + gallerySwitchStrategy: 'replace', + + // whether swatches are rendered in product list or on product page + inProductList: false, + + // sly-old-price block selector + slyOldPriceSelector: '.sly-old-price', + + // tier prise selectors start + tierPriceTemplateSelector: '#tier-prices-template', + tierPriceBlockSelector: '[data-role="tier-price-block"]', + tierPriceTemplate: '' + // tier prise selectors end }, /** @@ -208,11 +283,15 @@ define([ */ _init: function () { if (this.options.jsonConfig !== '' && this.options.jsonSwatchConfig !== '') { + // store unsorted attributes + this.options.jsonConfig.mappedAttributes = _.clone(this.options.jsonConfig.attributes); this._sortAttributes(); this._RenderControls(); + $(this.element).trigger('swatch.initialized'); } else { console.log('SwatchRenderer: No input data received'); } + this.options.tierPriceTemplate = $(this.options.tierPriceTemplateSelector).html(); }, /** @@ -236,17 +315,17 @@ define([ this.element.parents('.product-item-info'); if (isProductViewExist) { - gallery.on('gallery:loaded', function () { - var galleryObject = gallery.data('gallery'); - - options.mediaGalleryInitial = galleryObject.returnCurrentImages(); - }); + gallery.data('gallery') ? + this._onGalleryLoaded(gallery) : + gallery.on('gallery:loaded', this._onGalleryLoaded.bind(this, gallery)); } else { options.mediaGalleryInitial = [{ 'img': $main.find('.product-image-photo').attr('src') }]; } - this.productForm = this.element.parents(this.options.selectorProduct).find('form:first'); + + this.productForm = this.element.parents(this.options.selectorProductTile).find('form:first'); + this.inProductList = this.productForm.length > 0; }, /** @@ -264,9 +343,11 @@ define([ $.each(this.options.jsonConfig.attributes, function () { var item = this, - options = $widget._RenderSwatchOptions(item), + controlLabelId = 'option-label-' + item.code + '-' + item.id, + options = $widget._RenderSwatchOptions(item, controlLabelId), select = $widget._RenderSwatchSelect(item, chooseText), input = $widget._RenderFormInput(item), + listLabel = '', label = ''; // Show only swatch controls @@ -276,22 +357,32 @@ define([ if ($widget.options.enableControlLabel) { label += - '' + item.label + '' + + '' + + item.label + + '' + ''; } - if ($widget.productForm) { + if ($widget.inProductList) { $widget.productForm.append(input); input = ''; + listLabel = 'aria-label="' + item.label + '"'; + } else { + listLabel = 'aria-labelledby="' + controlLabelId + '"'; } // Create new control container.append( - '
    ' + - label + - '
    ' + + '
    ' + + label + + '
    ' + options + select + '
    ' + input + '
    ' @@ -336,10 +427,11 @@ define([ * Render swatch options by part of config * * @param {Object} config + * @param {String} controlId * @returns {String} * @private */ - _RenderSwatchOptions: function (config) { + _RenderSwatchOptions: function (config, controlId) { var optionConfig = this.options.jsonSwatchConfig[config.id], optionClass = this.options.classes.optionClass, moreLimit = parseInt(this.options.numberToShow, 10), @@ -375,11 +467,17 @@ define([ thumb = optionConfig[id].hasOwnProperty('thumb') ? optionConfig[id].thumb : ''; label = this.label ? this.label : ''; attr = + ' id="' + controlId + '-item-' + id + '"' + + ' aria-checked="false"' + + ' aria-describedby="' + controlId + '"' + + ' tabindex="0"' + ' option-type="' + type + '"' + ' option-id="' + id + '"' + ' option-label="' + label + '"' + + ' aria-label="' + label + '"' + ' option-tooltip-thumb="' + thumb + '"' + - ' option-tooltip-value="' + value + '"'; + ' option-tooltip-value="' + value + '"' + + ' role="option"'; if (!this.hasOwnProperty('products') || this.products.length <= 0) { attr += ' option-empty="true"'; @@ -392,19 +490,19 @@ define([ } else if (type === 1) { // Color html += '
    ' + '' + '
    '; } else if (type === 2) { // Image html += '
    ' + '' + + ' style="background: url(' + value + ') no-repeat center; background-size: initial;">' + '' + '
    '; } else if (type === 3) { // Clear html += '
    '; } else { - // Defaualt + // Default html += '
    ' + label + '
    '; } }); @@ -460,10 +558,9 @@ define([ 'type="text" ' + 'value="" ' + 'data-selector="super_attribute[' + config.id + ']" ' + - 'data-validate="{required:true}" ' + + 'data-validate="{required: true}" ' + 'aria-required="true" ' + - 'aria-invalid="true" ' + - 'style="visibility: hidden; position:absolute; left:-1000px">'; + 'aria-invalid="false">'; }, /** @@ -472,22 +569,39 @@ define([ * @private */ _EventListener: function () { + var $widget = this, + options = this.options.classes, + target; - var $widget = this; - - $widget.element.on('click', '.' + this.options.classes.optionClass, function () { + $widget.element.on('click', '.' + options.optionClass, function () { return $widget._OnClick($(this), $widget); }); - $widget.element.on('change', '.' + this.options.classes.selectClass, function () { + $widget.element.on('change', '.' + options.selectClass, function () { return $widget._OnChange($(this), $widget); }); - $widget.element.on('click', '.' + this.options.classes.moreButton, function (e) { + $widget.element.on('click', '.' + options.moreButton, function (e) { e.preventDefault(); return $widget._OnMoreClick($(this)); }); + + $widget.element.on('keydown', function (e) { + if (e.which === 13) { + target = $(e.target); + + if (target.is('.' + options.optionClass)) { + return $widget._OnClick(target, $widget); + } else if (target.is('.' + options.selectClass)) { + return $widget._OnChange(target, $widget); + } else if (target.is('.' + options.moreButton)) { + e.preventDefault(); + + return $widget._OnMoreClick(target); + } + } + }); }, /** @@ -498,13 +612,17 @@ define([ * @private */ _OnClick: function ($this, $widget) { - var $parent = $this.parents('.' + $widget.options.classes.attributeClass), + $wrapper = $this.parents('.' + $widget.options.classes.attributeOptionsWrapper), $label = $parent.find('.' + $widget.options.classes.attributeSelectedOptionLabelClass), attributeId = $parent.attr('attribute-id'), + $input = $parent.find('.' + $widget.options.classes.attributeInput); + + if ($widget.inProductList) { $input = $widget.productForm.find( '.' + $widget.options.classes.attributeInput + '[name="super_attribute[' + attributeId + ']"]' ); + } if ($this.hasClass('disabled')) { return; @@ -514,11 +632,14 @@ define([ $parent.removeAttr('option-selected').find('.selected').removeClass('selected'); $input.val(''); $label.text(''); + $this.attr('aria-checked', false); } else { $parent.attr('option-selected', $this.attr('option-id')).find('.selected').removeClass('selected'); $label.text($this.attr('option-label')); $input.val($this.attr('option-id')); + $input.attr('data-attr-name', this._getAttributeCodeById(attributeId)); $this.addClass('selected'); + $widget._toggleCheckedAttributes($this, $wrapper); } $widget._Rebuild(); @@ -533,6 +654,32 @@ define([ $input.trigger('change'); }, + /** + * Get human readable attribute code (eg. size, color) by it ID from configuration + * + * @param {Number} attributeId + * @returns {*} + * @private + */ + _getAttributeCodeById: function (attributeId) { + var attribute = this.options.jsonConfig.mappedAttributes[attributeId]; + + return attribute ? attribute.code : attributeId; + }, + + /** + * Toggle accessibility attributes + * + * @param {Object} $this + * @param {Object} $wrapper + * @private + */ + _toggleCheckedAttributes: function ($this, $wrapper) { + $wrapper.attr('aria-activedescendant', $this.attr('id')) + .find('.' + this.options.classes.optionClass).attr('aria-checked', false); + $this.attr('aria-checked', true); + }, + /** * Event for select * @@ -543,9 +690,13 @@ define([ _OnChange: function ($this, $widget) { var $parent = $this.parents('.' + $widget.options.classes.attributeClass), attributeId = $parent.attr('attribute-id'), + $input = $parent.find('.' + $widget.options.classes.attributeInput); + + if ($widget.productForm.length > 0) { $input = $widget.productForm.find( '.' + $widget.options.classes.attributeInput + '[name="super_attribute[' + attributeId + ']"]' ); + } if ($this.val() > 0) { $parent.attr('option-selected', $this.val()); @@ -671,7 +822,8 @@ define([ $product = $widget.element.parents($widget.options.selectorProduct), $productPrice = $product.find(this.options.selectorProductPrice), options = _.object(_.keys($widget.optionsMap), {}), - result; + result, + tierPriceHtml; $widget.element.find('.' + $widget.options.classes.attributeClass + '[option-selected]').each(function () { var attributeId = $(this).attr('attribute-id'); @@ -688,6 +840,28 @@ define([ } ); + if (result.oldPrice.amount !== result.finalPrice.amount) { + $(this.options.slyOldPriceSelector).show(); + } else { + $(this.options.slyOldPriceSelector).hide(); + } + + if (result.tierPrices.length) { + if (this.options.tierPriceTemplate) { + tierPriceHtml = mageTemplate( + this.options.tierPriceTemplate, + { + 'tierPrices': result.tierPrices, + '$t': $t, + 'currencyFormat': this.options.jsonConfig.currencyFormat, + 'priceUtils': priceUtils + } + ); + $(this.options.tierPriceBlockSelector).html(tierPriceHtml).show(); + } + } else { + $(this.options.tierPriceBlockSelector).hide(); + } }, /** @@ -900,26 +1074,27 @@ define([ */ updateBaseImage: function (images, context, isProductViewExist) { var justAnImage = images[0], - updateImg, - imagesToUpdate, + initialImages = this.options.mediaGalleryInitial, gallery = context.find(this.options.mediaGallerySelector).data('gallery'), - item; + imagesToUpdate, + isInitial; if (isProductViewExist) { imagesToUpdate = images.length ? this._setImageType($.extend(true, [], images)) : []; + isInitial = _.isEqual(imagesToUpdate, initialImages); - if (this.options.onlyMainImg) { - updateImg = imagesToUpdate.filter(function (img) { - return img.isMain; - }); - item = updateImg.length ? updateImg[0] : imagesToUpdate[0]; - gallery.updateDataByIndex(0, item); + if (this.options.gallerySwitchStrategy === 'prepend' && !isInitial) { + imagesToUpdate = imagesToUpdate.concat(initialImages); + } - gallery.seek(1); - } else { - gallery.updateData(imagesToUpdate); + gallery.updateData(imagesToUpdate); + + if (isInitial) { $(this.options.mediaGallerySelector).AddFotoramaVideoEvents(); } + + gallery.first(); + } else if (justAnImage && justAnImage.img) { context.find('.product-image-photo').attr('src', justAnImage.img); } @@ -951,6 +1126,30 @@ define([ }, this)); }, + /** + * Emulate mouse click or selection change on all swatches that should be selected + * @param {Object} [selectedAttributes] + * @private + */ + _EmulateSelectedByAttributeId: function (selectedAttributes) { + $.each(selectedAttributes, $.proxy(function (attributeId, optionId) { + var elem = this.element.find('.' + this.options.classes.attributeClass + + '[attribute-id="' + attributeId + '"] [option-id="' + optionId + '"]'), + parentInput = elem.parent(); + + if (elem.hasClass('selected')) { + return; + } + + if (parentInput.hasClass(this.options.classes.selectClass)) { + parentInput.val(optionId); + parentInput.trigger('change'); + } else { + elem.trigger('click'); + } + }, this)); + }, + /** * Get default options values settings with either URL query parameters * @private @@ -964,13 +1163,24 @@ define([ params = $.parseQuery(window.location.href.substr(hashIndex + 1)); selectedAttributes = _.invert(_.mapObject(_.invert(params), function (attributeId) { - var attribute = this.options.jsonConfig.attributes[attributeId]; + var attribute = this.options.jsonConfig.mappedAttributes[attributeId]; return attribute ? attribute.code : attributeId; }.bind(this))); } return selectedAttributes; + }, + + /** + * Callback which fired after gallery gets initialized. + * + * @param {HTMLElement} element - DOM element associated with a gallery. + */ + _onGalleryLoaded: function (element) { + var galleryObject = element.data('gallery'); + + this.options.mediaGalleryInitial = galleryObject.returnCurrentImages(); } }); diff --git a/app/code/Magento/SwatchesLayeredNavigation/composer.json b/app/code/Magento/SwatchesLayeredNavigation/composer.json index 9b658d0a42e61..67c6d90c51e7f 100644 --- a/app/code/Magento/SwatchesLayeredNavigation/composer.json +++ b/app/code/Magento/SwatchesLayeredNavigation/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-swatches-layered-navigation", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/framework": "100.2.*", "magento/magento-composer-installer": "*" }, diff --git a/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml b/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml index 1b91e7da1e5b6..403b13a54ed98 100644 --- a/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml +++ b/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/SwatchesLayeredNavigation/registration.php b/app/code/Magento/SwatchesLayeredNavigation/registration.php index 164603e6b531e..ea1540b617d26 100644 --- a/app/code/Magento/SwatchesLayeredNavigation/registration.php +++ b/app/code/Magento/SwatchesLayeredNavigation/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php b/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php index cbab5a59d34c7..1860097fec100 100644 --- a/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php +++ b/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php @@ -1,6 +1,6 @@ priceCurrency = $priceCurrency; @@ -130,6 +137,7 @@ public function __construct( $this->_localeResolver = $localeResolver; $this->catalogHelper = $catalogHelper; $this->orderTaxManagement = $orderTaxManagement; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); } /** @@ -738,7 +746,7 @@ protected function calculateTaxForItems(EntityInterface $order, EntityInterface $taxableItemType = $itemTaxDetail->getType(); $ratio = $itemRatio; if ($item->getTaxRatio()) { - $taxRatio = unserialize($item->getTaxRatio()); + $taxRatio = $this->serializer->unserialize($item->getTaxRatio()); if (isset($taxRatio[$taxableItemType])) { $ratio = $taxRatio[$taxableItemType]; } diff --git a/app/code/Magento/Tax/Model/AggregateSalesReportTaxData.php b/app/code/Magento/Tax/Model/AggregateSalesReportTaxData.php index b12fe5d15143b..05de4592d26a4 100644 --- a/app/code/Magento/Tax/Model/AggregateSalesReportTaxData.php +++ b/app/code/Magento/Tax/Model/AggregateSalesReportTaxData.php @@ -1,6 +1,6 @@ _scopeConfig->getValue( + self::XML_PATH_TAX_NOTIFICATION_IGNORE_APPLY_DISCOUNT, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + $store + ); + } + /** * Check if do not show notification about wrong display settings * diff --git a/app/code/Magento/Tax/Model/Config/Notification.php b/app/code/Magento/Tax/Model/Config/Notification.php index fc7edf677e8a3..cc2c17a7276fa 100644 --- a/app/code/Magento/Tax/Model/Config/Notification.php +++ b/app/code/Magento/Tax/Model/Config/Notification.php @@ -1,11 +1,12 @@ isValueChanged()) { - $this->_resetNotificationFlag(\Magento\Tax\Model\Config::XML_PATH_TAX_NOTIFICATION_IGNORE_DISCOUNT); - $this->_resetNotificationFlag(\Magento\Tax\Model\Config::XML_PATH_TAX_NOTIFICATION_IGNORE_PRICE_DISPLAY); + $this->_resetNotificationFlag(Config::XML_PATH_TAX_NOTIFICATION_IGNORE_DISCOUNT); + $this->_resetNotificationFlag(Config::XML_PATH_TAX_NOTIFICATION_IGNORE_PRICE_DISPLAY); + $this->_resetNotificationFlag(Config::XML_PATH_TAX_NOTIFICATION_IGNORE_APPLY_DISCOUNT); } return parent::afterSave(); } diff --git a/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php b/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php index 40030a70e62b8..16b427367a094 100644 --- a/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php +++ b/app/code/Magento/Tax/Model/Config/Price/IncludePrice.php @@ -1,6 +1,6 @@ detailsFactory = $detailsFactory; $this->ratesFactory = $ratesFactory; $this->totalSegmentExtensionFactory = $totalSegmentExtensionFactory; $this->taxConfig = $taxConfig; + $this->serializer = $serializer; $this->code = 'tax'; } @@ -73,7 +85,6 @@ protected function getRatesData($rates) * @param \Magento\Quote\Model\Cart\TotalsConverter $subject * @param \Magento\Quote\Api\Data\TotalSegmentInterface[] $totalSegments * @param \Magento\Quote\Model\Quote\Address\Total[] $addressTotals - * * @return \Magento\Quote\Api\Data\TotalSegmentInterface[] * @SuppressWarnings(PHPMD.UnusedFormalParameter) * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -97,7 +108,7 @@ public function afterProcess( $finalData = []; $fullInfo = $taxes['full_info']; if (is_string($fullInfo)) { - $fullInfo = unserialize($fullInfo); + $fullInfo = $this->serializer->unserialize($fullInfo); } foreach ($fullInfo as $info) { if ((array_key_exists('hidden', $info) && $info['hidden']) diff --git a/app/code/Magento/Tax/Model/Quote/ToOrderConverter.php b/app/code/Magento/Tax/Model/Quote/ToOrderConverter.php index 858838b84c89d..17763dbdc5d84 100644 --- a/app/code/Magento/Tax/Model/Quote/ToOrderConverter.php +++ b/app/code/Magento/Tax/Model/Quote/ToOrderConverter.php @@ -1,6 +1,6 @@ setSubtotalInclTax($subtotalInclTax); $total->setBaseSubtotalTotalInclTax($baseSubtotalInclTax); $total->setBaseSubtotalInclTax($baseSubtotalInclTax); + $shippingAssignment->getShipping()->getAddress()->setBaseSubtotalTotalInclTax($baseSubtotalInclTax);; return $this; } diff --git a/app/code/Magento/Tax/Model/Sales/Total/Quote/Shipping.php b/app/code/Magento/Tax/Model/Sales/Total/Quote/Shipping.php index 29ff55ca27053..5460f6e3a58e1 100644 --- a/app/code/Magento/Tax/Model/Sales/Total/Quote/Shipping.php +++ b/app/code/Magento/Tax/Model/Sales/Total/Quote/Shipping.php @@ -1,6 +1,6 @@ setCode('tax'); $this->_taxData = $taxData; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); parent::__construct( $taxConfig, $taxCalculationService, @@ -300,7 +310,7 @@ public function fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Qu $store = $quote->getStore(); $applied = $total->getAppliedTaxes(); if (is_string($applied)) { - $applied = unserialize($applied); + $applied = $this->serializer->unserialize($applied); } $amount = $total->getTaxAmount(); if ($amount === null) { diff --git a/app/code/Magento/Tax/Model/System/Config/Source/Algorithm.php b/app/code/Magento/Tax/Model/System/Config/Source/Algorithm.php index d0815302d37de..60a004ed8a9ad 100644 --- a/app/code/Magento/Tax/Model/System/Config/Source/Algorithm.php +++ b/app/code/Magento/Tax/Model/System/Config/Source/Algorithm.php @@ -1,6 +1,6 @@ storeManager = $storeManager; + $this->urlBuilder = $urlBuilder; + $this->taxConfig = $taxConfig; + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function getIdentity() + { + return 'TAX_NOTIFICATION_APPLY_DISCOUNT'; + } + + /** + * {@inheritdoc} + */ + public function isDisplayed() + { + if (!$this->taxConfig->isWrongApplyDiscountSettingIgnored() && $this->getStoresWithWrongSettings()) { + return true; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function getText() + { + $messageDetails = ''; + + if ($this->isDisplayed()) { + $messageDetails .= ''; + $messageDetails .= __('To apply the discount on prices including tax and apply the tax after discount, set Catalog Prices to “Including Tax”. '); + $messageDetails .= '

    '; + $messageDetails .= __('Store(s) affected: '); + $messageDetails .= implode(', ', $this->getStoresWithWrongSettings()); + $messageDetails .= '

    '; + $messageDetails .= __( + 'Click on the link to ignore this notification', + $this->urlBuilder->getUrl('tax/tax/ignoreTaxNotification', ['section' => 'apply_discount']) + ); + $messageDetails .= "

    "; + } + + return $messageDetails; + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function getSeverity() + { + return self::SEVERITY_CRITICAL; + } + + /** + * Return list of store names which have invalid settings. + * + * @return array + */ + private function getStoresWithWrongSettings() + { + if (null !== $this->storesWithInvalidSettings) { + return $this->storesWithInvalidSettings; + } + $this->storesWithInvalidSettings = []; + $storeCollection = $this->storeManager->getStores(true); + foreach ($storeCollection as $store) { + if (!$this->checkSettings($store)) { + $website = $store->getWebsite(); + $this->storesWithInvalidSettings[] = $website->getName() . ' (' . $store->getName() . ')'; + } + } + return $this->storesWithInvalidSettings; + } + + /** + * Check if settings are valid. + * + * @param null|int|bool|string|\Magento\Store\Model\Store $store $store + * @return bool false if settings are incorrect + */ + private function checkSettings($store = null) + { + return $this->taxConfig->priceIncludesTax($store) + || !$this->taxConfig->applyTaxAfterDiscount($store) + || !$this->taxConfig->discountTax($store); + } +} diff --git a/app/code/Magento/Tax/Model/System/Message/Notification/DiscountErrors.php b/app/code/Magento/Tax/Model/System/Message/Notification/DiscountErrors.php new file mode 100644 index 0000000000000..fbb5359ff6ccc --- /dev/null +++ b/app/code/Magento/Tax/Model/System/Message/Notification/DiscountErrors.php @@ -0,0 +1,143 @@ +storeManager = $storeManager; + $this->urlBuilder = $urlBuilder; + $this->taxConfig = $taxConfig; + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function getIdentity() + { + return 'TAX_NOTIFICATION_DISCOUNT_ERRORS'; + } + + /** + * {@inheritdoc} + */ + public function isDisplayed() + { + if (!$this->taxConfig->isWrongDiscountSettingsIgnored() && $this->getStoresWithWrongSettings()) { + return true; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function getText() + { + $messageDetails = ''; + + if (!empty($this->getStoresWithWrongSettings()) && !$this->taxConfig->isWrongDiscountSettingsIgnored()) { + $messageDetails .= ''; + $messageDetails .= __('With customer tax applied “Before Discount”, the final discount calculation may not match customers’ expectations. '); + $messageDetails .= '

    '; + $messageDetails .= __('Store(s) affected: '); + $messageDetails .= implode(', ', $this->getStoresWithWrongSettings()); + $messageDetails .= '

    '; + $messageDetails .= __( + 'Click on the link to ignore this notification', + $this->urlBuilder->getUrl('tax/tax/ignoreTaxNotification', ['section' => 'discount']) + ); + $messageDetails .= "

    "; + } + + return $messageDetails; + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function getSeverity() + { + return self::SEVERITY_CRITICAL; + } + + /** + * Check if tax discount settings are compatible + * + * Matrix for invalid discount settings is as follows: + * Before Discount / Excluding Tax + * Before Discount / Including Tax + * + * @param null|int|bool|string|\Magento\Store\Model\Store $store $store + * @return bool + */ + private function checkSettings($store = null) + { + return $this->taxConfig->applyTaxAfterDiscount($store); + } + + /** + * Return list of store names where tax discount settings are compatible. + * Return true if settings are wrong for default store. + * + * @return array + */ + private function getStoresWithWrongSettings() + { + if (null !== $this->storesWithInvalidSettings) { + return $this->storesWithInvalidSettings; + } + $this->storesWithInvalidSettings = []; + $storeCollection = $this->storeManager->getStores(true); + foreach ($storeCollection as $store) { + if (!$this->checkSettings($store)) { + $website = $store->getWebsite(); + $this->storesWithInvalidSettings[] = $website->getName() . ' (' . $store->getName() . ')'; + } + } + return $this->storesWithInvalidSettings; + } +} diff --git a/app/code/Magento/Tax/Model/System/Message/Notification/RoundingErrors.php b/app/code/Magento/Tax/Model/System/Message/Notification/RoundingErrors.php new file mode 100644 index 0000000000000..d722a274df30f --- /dev/null +++ b/app/code/Magento/Tax/Model/System/Message/Notification/RoundingErrors.php @@ -0,0 +1,151 @@ +storeManager = $storeManager; + $this->urlBuilder = $urlBuilder; + $this->taxConfig = $taxConfig; + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function getIdentity() + { + return 'TAX_NOTIFICATION_ROUNDING_ERRORS'; + } + + /** + * {@inheritdoc} + */ + public function isDisplayed() + { + if (!$this->taxConfig->isWrongDisplaySettingsIgnored() && $this->getStoresWithWrongSettings()) { + return true; + } + return false; + } + + /** + * {@inheritdoc} + */ + public function getText() + { + $messageDetails = ''; + + if (!empty($this->getStoresWithWrongSettings()) && !$this->taxConfig->isWrongDisplaySettingsIgnored()) { + $messageDetails .= ''; + $messageDetails .= __('Your current tax configuration may result in rounding errors. '); + $messageDetails .= '

    '; + $messageDetails .= __('Store(s) affected: '); + $messageDetails .= implode(', ', $this->getStoresWithWrongSettings()); + $messageDetails .= '

    '; + $messageDetails .= __( + 'Click on the link to ignore this notification', + $this->urlBuilder->getUrl('tax/tax/ignoreTaxNotification', ['section' => 'price_display']) + ); + $messageDetails .= "

    "; + } + + return $messageDetails; + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function getSeverity() + { + return self::SEVERITY_CRITICAL; + } + + /** + * Check if tax calculation type and price display settings are compatible + * + * Invalid settings if + * Tax Calculation Method Based On 'Total' or 'Row' + * and at least one Price Display Settings has 'Including and Excluding Tax' value + * + * @param null|int|bool|string|\Magento\Store\Model\Store $store $store + * @return bool + */ + private function checkSettings($store = null) + { + if ($this->taxConfig->getAlgorithm($store) == \Magento\Tax\Model\Calculation::CALC_UNIT_BASE) { + return true; + } + return $this->taxConfig->getPriceDisplayType($store) != \Magento\Tax\Model\Config::DISPLAY_TYPE_BOTH + && $this->taxConfig->getShippingPriceDisplayType($store) != \Magento\Tax\Model\Config::DISPLAY_TYPE_BOTH + && !$this->taxConfig->displayCartPricesBoth($store) + && !$this->taxConfig->displayCartSubtotalBoth($store) + && !$this->taxConfig->displayCartShippingBoth($store) + && !$this->taxConfig->displaySalesPricesBoth($store) + && !$this->taxConfig->displaySalesSubtotalBoth($store) + && !$this->taxConfig->displaySalesShippingBoth($store); + } + + /** + * Return list of store names which have not compatible tax calculation type and price display settings. + * Return true if settings are wrong for default store. + * + * @return array + */ + private function getStoresWithWrongSettings() + { + if (null !== $this->storesWithInvalidSettings) { + return $this->storesWithInvalidSettings; + } + $this->storesWithInvalidSettings = []; + $storeCollection = $this->storeManager->getStores(true); + foreach ($storeCollection as $store) { + if (!$this->checkSettings($store)) { + $website = $store->getWebsite(); + $this->storesWithInvalidSettings[] = $website->getName() . ' (' . $store->getName() . ')'; + } + } + return $this->storesWithInvalidSettings; + } +} diff --git a/app/code/Magento/Tax/Model/System/Message/NotificationInterface.php b/app/code/Magento/Tax/Model/System/Message/NotificationInterface.php new file mode 100644 index 0000000000000..4f230d1584648 --- /dev/null +++ b/app/code/Magento/Tax/Model/System/Message/NotificationInterface.php @@ -0,0 +1,13 @@ +storeManager = $storeManager; $this->urlBuilder = $urlBuilder; $this->taxConfig = $taxConfig; + $this->notifications = $notifications; } /** * Retrieve unique message identity * * @return string + * @codeCoverageIgnore */ public function getIdentity() { return md5('TAX_NOTIFICATION'); } + /** + * {@inheritdoc} + */ + public function isDisplayed() + { + foreach ($this->notifications as $notification) { + if ($notification->isDisplayed()) { + return true; + } + } + return false; + } + + /** + * {@inheritdoc} + */ + public function getText() + { + $messageDetails = ''; + + foreach ($this->notifications as $notification) { + $messageDetails .= $notification->getText(); + } + + $messageDetails .= '

    '; + $messageDetails .= __('Please see documentation for more details. ', $this->getInfoUrl()); + $messageDetails .= __( + 'Click here to go to Tax Configuration and change your settings.', + $this->getManageUrl() + ); + $messageDetails .= '

    '; + + return $messageDetails; + } + + /** + * Retrieve message severity + * + * @return int + * @codeCoverageIgnore + */ + public function getSeverity() + { + return self::SEVERITY_CRITICAL; + } + + /** + * Get URL for the tax notification documentation + * + * @return string + */ + public function getInfoUrl() + { + return $this->taxConfig->getInfoUrl(); + } + + /** + * Get URL to the admin tax configuration page + * + * @return string + */ + public function getManageUrl() + { + return $this->urlBuilder->getUrl('adminhtml/system_config/edit/section/tax'); + } + /** * Check if tax calculation type and price display settings are compatible * @@ -77,6 +157,8 @@ public function getIdentity() * * @param null|int|bool|string|\Magento\Store\Model\Store $store $store * @return bool + * @deprecated + * @see \Magento\Tax\Model\System\Message\Notification\RoundingErrors::checkSettings */ public function checkDisplaySettings($store = null) { @@ -84,13 +166,13 @@ public function checkDisplaySettings($store = null) return true; } return $this->taxConfig->getPriceDisplayType($store) != \Magento\Tax\Model\Config::DISPLAY_TYPE_BOTH - && $this->taxConfig->getShippingPriceDisplayType($store) != \Magento\Tax\Model\Config::DISPLAY_TYPE_BOTH - && !$this->taxConfig->displayCartPricesBoth($store) - && !$this->taxConfig->displayCartSubtotalBoth($store) - && !$this->taxConfig->displayCartShippingBoth($store) - && !$this->taxConfig->displaySalesPricesBoth($store) - && !$this->taxConfig->displaySalesSubtotalBoth($store) - && !$this->taxConfig->displaySalesShippingBoth($store); + && $this->taxConfig->getShippingPriceDisplayType($store) != \Magento\Tax\Model\Config::DISPLAY_TYPE_BOTH + && !$this->taxConfig->displayCartPricesBoth($store) + && !$this->taxConfig->displayCartSubtotalBoth($store) + && !$this->taxConfig->displayCartShippingBoth($store) + && !$this->taxConfig->displaySalesPricesBoth($store) + && !$this->taxConfig->displaySalesSubtotalBoth($store) + && !$this->taxConfig->displaySalesShippingBoth($store); } /** @@ -102,37 +184,20 @@ public function checkDisplaySettings($store = null) * * @param null|int|bool|string|\Magento\Store\Model\Store $store $store * @return bool + * @deprecated + * @see \Magento\Tax\Model\System\Message\Notification\DiscountErrors::checkSettings */ public function checkDiscountSettings($store = null) { return $this->taxConfig->applyTaxAfterDiscount($store); } - /** - * Get URL for the tax notification documentation - * - * @return string - */ - public function getInfoUrl() - { - return $this->taxConfig->getInfoUrl(); - } - - /** - * Get URL to the admin tax configuration page - * - * @return string - */ - public function getManageUrl() - { - return $this->urlBuilder->getUrl('adminhtml/system_config/edit/section/tax'); - } - /** * Get URL to ignore tax notifications * * @param string $section * @return string + * @deprecated */ public function getIgnoreTaxNotificationUrl($section) { @@ -144,6 +209,8 @@ public function getIgnoreTaxNotificationUrl($section) * Return true if settings are wrong for default store. * * @return array + * @deprecated + * @see \Magento\Tax\Model\System\Message\Notification\RoundingErrors::getStoresWithWrongSettings */ public function getStoresWithWrongDisplaySettings() { @@ -163,6 +230,8 @@ public function getStoresWithWrongDisplaySettings() * Return true if settings are wrong for default store. * * @return array + * @deprecated + * @see \Magento\Tax\Model\System\Message\Notification\DiscountErrors::getStoresWithWrongSettings */ public function getStoresWithWrongDiscountSettings() { @@ -176,94 +245,4 @@ public function getStoresWithWrongDiscountSettings() } return $storeNames; } - - /** - * Check whether notification is displayed - * Checks if any of these settings are being ignored or valid: - * 1. Wrong discount settings - * 2. Wrong display settings - * - * @return bool - */ - public function isDisplayed() - { - // Check if we are ignoring all notifications - if ($this->taxConfig->isWrongDisplaySettingsIgnored() && $this->taxConfig->isWrongDiscountSettingsIgnored()) { - return false; - } - - $this->storesWithInvalidDisplaySettings = $this->getStoresWithWrongDisplaySettings(); - $this->storesWithInvalidDiscountSettings = $this->getStoresWithWrongDiscountSettings(); - - // Check if we have valid tax notifications - if ((!empty($this->storesWithInvalidDisplaySettings) && !$this->taxConfig->isWrongDisplaySettingsIgnored()) - || (!empty($this->storesWithInvalidDiscountSettings) && !$this->taxConfig->isWrongDiscountSettingsIgnored()) - ) { - return true; - } - - return false; - } - - /** - * Build message text - * Determine which notification and data to display - * - * @return string - */ - public function getText() - { - $messageDetails = ''; - - if (!empty($this->storesWithInvalidDisplaySettings) && !$this->taxConfig->isWrongDisplaySettingsIgnored()) { - $messageDetails .= ''; - $messageDetails .= __('Warning tax configuration can result in rounding errors. '); - $messageDetails .= '

    '; - $messageDetails .= __('Store(s) affected: '); - $messageDetails .= implode(', ', $this->storesWithInvalidDisplaySettings); - $messageDetails .= '

    '; - $messageDetails .= __( - 'Click on the link to ignore this notification', - $this->getIgnoreTaxNotificationUrl('price_display') - ); - $messageDetails .= "

    "; - } - - if (!empty($this->storesWithInvalidDiscountSettings) && !$this->taxConfig->isWrongDiscountSettingsIgnored()) { - $messageDetails .= ''; - $messageDetails .= __( - 'Warning tax discount configuration might result in different discounts - than a customer might expect. ' - ); - $messageDetails .= '

    '; - $messageDetails .= __('Store(s) affected: '); - $messageDetails .= implode(', ', $this->storesWithInvalidDiscountSettings); - $messageDetails .= '

    '; - $messageDetails .= __( - 'Click on the link to ignore this notification', - $this->getIgnoreTaxNotificationUrl('discount') - ); - $messageDetails .= "

    "; - } - - $messageDetails .= '

    '; - $messageDetails .= __('Please see documentation for more details. ', $this->getInfoUrl()); - $messageDetails .= __( - 'Click here to go to Tax Configuration and change your settings.', - $this->getManageUrl() - ); - $messageDetails .= '

    '; - - return $messageDetails; - } - - /** - * Retrieve message severity - * - * @return int - */ - public function getSeverity() - { - return self::SEVERITY_CRITICAL; - } } diff --git a/app/code/Magento/Tax/Model/TaxCalculation.php b/app/code/Magento/Tax/Model/TaxCalculation.php index 4edcfaa7aa34f..59ec3b060ac0a 100644 --- a/app/code/Magento/Tax/Model/TaxCalculation.php +++ b/app/code/Magento/Tax/Model/TaxCalculation.php @@ -1,6 +1,6 @@ taxConfigMock = $this->getMockBuilder(\Magento\Tax\Model\Config::class) ->disableOriginalConstructor() ->getMock(); + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->getMock(); + $this->serializer->expects($this->any()) + ->method('serialize') + ->willReturnCallback( + function ($value) { + return json_encode($value); + } + ); - $this->helper = $objectManager->getObject( + $this->serializer->expects($this->any()) + ->method('unserialize') + ->willReturnCallback( + function ($value) { + return json_decode($value, true); + } + ); + $this->helper = $objectManager->getObject( \Magento\Tax\Helper\Data::class, [ 'orderTaxManagement' => $this->orderTaxManagementMock, 'priceCurrency' => $this->priceCurrencyMock, - 'taxConfig' => $this->taxConfigMock + 'taxConfig' => $this->taxConfigMock, + 'serializer' => $this->serializer ] ); } @@ -147,7 +170,7 @@ protected function mapOrderTaxItemDetail($inputArray) $appliedTaxesData = $orderTaxDetailsItemData['applied_taxes']; $appliedTaxesMocks = []; foreach ($appliedTaxesData as $appliedTaxData) { - $appliedTaxesMock = $this->getMockBuilder( + $appliedTaxesMock = $this->getMockBuilder( \Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterface::class) ->getMock(); $appliedTaxesMock->expects($this->any()) @@ -363,7 +386,7 @@ public function getCalculatedTaxesForOrderItemsDataProvider() ), 'tax_amount' => 5.0, //half of weee tax is invoiced - 'tax_ratio' => serialize(['weee' => 0.5]), + 'tax_ratio' => json_encode(['weee' => 0.5]), ] ), ], diff --git a/app/code/Magento/Tax/Test/Unit/Model/Calculation/CalculatorFactoryTest.php b/app/code/Magento/Tax/Test/Unit/Model/Calculation/CalculatorFactoryTest.php index 725b35a485c8f..8841df70bf6be 100644 --- a/app/code/Magento/Tax/Test/Unit/Model/Calculation/CalculatorFactoryTest.php +++ b/app/code/Magento/Tax/Test/Unit/Model/Calculation/CalculatorFactoryTest.php @@ -1,6 +1,6 @@ disableOriginalConstructor() ->getMock(); + $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->getMock(); + + $serializer->expects($this->any()) + ->method('serialize') + ->willReturnCallback( + function ($value) { + return json_encode($value); + } + ); + + $serializer->expects($this->any()) + ->method('unserialize') + ->willReturnCallback( + function ($value) { + return json_decode($value, true); + } + ); + $this->objectManagerHelper = new ObjectManager($this); $this->model = $this->objectManagerHelper->getObject( \Magento\Tax\Model\Quote\GrandTotalDetailsPlugin::class, @@ -83,6 +103,7 @@ protected function setUp() 'ratesFactory' => $this->ratesFactoryMock, 'detailsFactory' => $this->detailsFactoryMock, 'taxConfig' => $this->taxConfigMock, + 'serializer' => $serializer ] ); } @@ -166,12 +187,12 @@ public function testAfterProcess() ); $taxTotalData = [ - 'full_info' => [ + 'full_info' => json_encode([ [ 'amount' => $taxAmount, 'rates' => [$taxRate], ], - ], + ]), ]; $taxTotalMock = $this->setupTaxTotal($taxTotalData); $addressTotals = [ diff --git a/app/code/Magento/Tax/Test/Unit/Model/Quote/ToOrderConverterTest.php b/app/code/Magento/Tax/Test/Unit/Model/Quote/ToOrderConverterTest.php index d276c5fb53428..892f50930a471 100644 --- a/app/code/Magento/Tax/Test/Unit/Model/Quote/ToOrderConverterTest.php +++ b/app/code/Magento/Tax/Test/Unit/Model/Quote/ToOrderConverterTest.php @@ -1,6 +1,6 @@ markTestIncomplete('Source code is not testable. Need to be refactored before unit testing'); $shippingAssignmentMock = $this->getMock(\Magento\Quote\Api\Data\ShippingAssignmentInterface::class); @@ -247,8 +247,8 @@ public function testCollect($itemData, $appliedRatesData, $taxDetailsData, $quot $address = $this->getMockBuilder(\Magento\Quote\Model\Quote\Address::class) ->disableOriginalConstructor() ->setMethods(['getAssociatedTaxables', - 'getQuote', 'getBillingAddress', 'getRegionId', - '__wakeup', 'getCustomAttributesCodes']) + 'getQuote', 'getBillingAddress', 'getRegionId', + '__wakeup', 'getCustomAttributesCodes']) ->getMock(); $item ->expects($this->any()) @@ -613,13 +613,36 @@ public function testFetch($appliedTaxesData, $addressData) ->will($this->returnValue(true)); $objectManager = new ObjectManager($this); + + $serializer = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->disableOriginalConstructor() + ->getMock(); + + $serializer->expects($this->any()) + ->method('serialize') + ->willReturnCallback( + function ($value) { + return json_encode($value); + } + ); + + $serializer->expects($this->any()) + ->method('unserialize') + ->willReturnCallback( + function ($value) { + return json_decode($value, true); + } + ); + /** @var \Magento\Tax\Model\Sales\Total\Quote\Tax $taxTotalsCalcModel */ $taxTotalsCalcModel = $objectManager->getObject( \Magento\Tax\Model\Sales\Total\Quote\Tax::class, - ['taxConfig' => $taxConfig] + [ + 'taxConfig' => $taxConfig, + 'serializer' => $serializer + ] ); - $appliedTaxes = unserialize($appliedTaxesData); $store = $this->getMockBuilder(\Magento\Store\Model\Store::class) ->disableOriginalConstructor() ->setMethods(['convertPrice', '__wakeup']) @@ -641,7 +664,7 @@ public function testFetch($appliedTaxesData, $addressData) $totalsMock ->expects($this->once()) ->method('getAppliedTaxes') - ->will($this->returnValue($appliedTaxes)); + ->will($this->returnValue($appliedTaxesData)); $totalsMock ->expects($this->any()) ->method('getGrandTotal') @@ -675,6 +698,7 @@ public function testFetch($appliedTaxesData, $addressData) $totalsArray = $taxTotalsCalcModel->fetch($quote, $totalsMock); $this->assertArrayHasKey('value', $totalsArray[0]); $this->assertEquals($taxAmount, $totalsArray[0]['value']); + $this->assertEquals(json_decode($appliedTaxesData, true), $totalsArray[0]['full_info']); } /** @@ -685,10 +709,26 @@ public function testFetch($appliedTaxesData, $addressData) */ public function dataProviderFetchArray() { - $appliedDataString = 'a:1:{s:7:"TX Rate";a:9:{s:6:"amount";d:80;s:11:"base_amount";d:80;s:7:"percent";'; - $appliedDataString .= 'd:10;s:2:"id";s:7:"TX Rate";s:5:"rates";a:1:{i:0;a:3:{s:7:"percent";d:10;s:4:"code";'; - $appliedDataString .= 's:7:"TX Rate";s:5:"title";s:7:"TX Rate";}}s:7:"item_id";s:1:"1";s:9:"item_type";'; - $appliedDataString .= 's:7:"product";s:18:"associated_item_id";N;s:7:"process";i:0;}}'; + $appliedDataString = [ + 'amount' => 80.0, + 'base_amount' => 80.0, + 'percent' => 10.0, + 'id' => 'TX Rate', + 'rates' => [ + 0 => [ + 'percent' => 10.0, + 'code' => 'TX Rate', + 'title' => 'TX Rate', + ], + ], + 'item_id' => '1', + 'item_type' => 'product', + 'associated_item_id' => NULL, + 'process' => 0, + ]; + + $appliedDataString = json_encode($appliedDataString); + $data = [ 'default' => [ 'appliedTaxesData' => $appliedDataString, diff --git a/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/ApplyDiscountOnPricesTest.php b/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/ApplyDiscountOnPricesTest.php new file mode 100644 index 0000000000000..99619bff252cc --- /dev/null +++ b/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/ApplyDiscountOnPricesTest.php @@ -0,0 +1,160 @@ +getMock(WebsiteInterface::class, [], [], '', false); + $websiteMock->expects($this->any())->method('getName')->willReturn('testWebsiteName'); + $storeMock = $this->getMockForAbstractClass( + StoreInterface::class, + [], + '', + false, + true, + true, + ['getWebsite', 'getName'] + ); + $storeMock->expects($this->any())->method('getName')->willReturn('testStoreName'); + $storeMock->expects($this->any())->method('getWebsite')->willReturn($websiteMock); + $this->storeManagerMock = $this->getMock(StoreManagerInterface::class, [], [], '', false); + $this->storeManagerMock->expects($this->any())->method('getStores')->willReturn([$storeMock]); + + $this->urlBuilderMock = $this->getMock(UrlInterface::class, [], [], '', false); + $this->taxConfigMock = $this->getMock(TaxConfig::class, [], [], '', false); + $this->applyDiscountOnPricesNotification = (new ObjectManager($this))->getObject( + ApplyDiscountOnPricesNotification::class, + [ + 'storeManager' => $this->storeManagerMock, + 'urlBuilder' => $this->urlBuilderMock, + 'taxConfig' => $this->taxConfigMock, + ] + ); + } + + /** + * @dataProvider dataProviderIsDisplayed + */ + public function testIsDisplayed( + $isWrongApplyDiscountSettingIgnored, + $priceIncludesTax, + $applyTaxAfterDiscount, + $discountTax, + $expectedResult + ) { + $this->taxConfigMock->expects($this->any())->method('isWrongApplyDiscountSettingIgnored') + ->willReturn($isWrongApplyDiscountSettingIgnored); + $this->taxConfigMock->expects($this->any())->method('priceIncludesTax')->willReturn($priceIncludesTax); + $this->taxConfigMock->expects($this->any())->method('applyTaxAfterDiscount') + ->willReturn($applyTaxAfterDiscount); + $this->taxConfigMock->expects($this->any())->method('discountTax')->willReturn($discountTax); + + $this->assertEquals($expectedResult, $this->applyDiscountOnPricesNotification->isDisplayed()); + } + + public function dataProviderIsDisplayed() + { + return [ + [ + false, // $isWrongApplyDiscountSettingIgnored, + false, // $priceIncludesTax, + true, // $applyTaxAfterDiscount, + true, // $discountTax, + true // $expectedResult + ], + [ + false, // $isWrongApplyDiscountSettingIgnored, + false, // $priceIncludesTax, + true, // $applyTaxAfterDiscount, + false, // $discountTax, + false // $expectedResult + ], + [ + false, // $isWrongApplyDiscountSettingIgnored, + false, // $priceIncludesTax, + false, // $applyTaxAfterDiscount, + true, // $discountTax, + false // $expectedResult + ], + [ + false, // $isWrongApplyDiscountSettingIgnored, + true, // $priceIncludesTax, + true, // $applyTaxAfterDiscount, + true, // $discountTax, + false // $expectedResult + ], + [ + true, // $isWrongApplyDiscountSettingIgnored, + false, // $priceIncludesTax, + true, // $applyTaxAfterDiscount, + true, // $discountTax, + false // $expectedResult + ] + ]; + } + + public function testGetText() + { + $this->taxConfigMock->expects($this->any())->method('isWrongApplyDiscountSettingIgnored')->willReturn(false); + + $this->taxConfigMock->expects($this->any())->method('priceIncludesTax')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('applyTaxAfterDiscount')->willReturn(true); + $this->taxConfigMock->expects($this->any())->method('discountTax')->willReturn(true); + + $this->urlBuilderMock->expects($this->any()) + ->method('getUrl') + ->with('tax/tax/ignoreTaxNotification', ['section' => 'apply_discount']) + ->willReturn('http://example.com'); + $this->applyDiscountOnPricesNotification->isDisplayed(); + $this->assertEquals( + 'To apply the discount on prices including tax and apply the tax after discount, ' + . 'set Catalog Prices to “Including Tax”.

    Store(s) affected: testWebsiteName ' + . '(testStoreName)

    Click on the link to ' + . 'ignore this notification

    ', + $this->applyDiscountOnPricesNotification->getText() + ); + } +} diff --git a/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/DiscountErrorsTest.php b/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/DiscountErrorsTest.php new file mode 100644 index 0000000000000..0ea0b68ebf4b8 --- /dev/null +++ b/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/DiscountErrorsTest.php @@ -0,0 +1,103 @@ +getMock(WebsiteInterface::class, [], [], '', false); + $websiteMock->expects($this->any())->method('getName')->willReturn('testWebsiteName'); + $storeMock = $this->getMockForAbstractClass( + StoreInterface::class, + [], + '', + false, + true, + true, + ['getWebsite', 'getName'] + ); + $storeMock->expects($this->any())->method('getName')->willReturn('testStoreName'); + $storeMock->expects($this->any())->method('getWebsite')->willReturn($websiteMock); + $this->storeManagerMock = $this->getMock(StoreManagerInterface::class, [], [], '', false); + $this->storeManagerMock->expects($this->any())->method('getStores')->willReturn([$storeMock]); + + $this->urlBuilderMock = $this->getMock(UrlInterface::class, [], [], '', false); + $this->taxConfigMock = $this->getMock(TaxConfig::class, [], [], '', false); + $this->discountErrorsNotification = (new ObjectManager($this))->getObject( + DiscountErrorsNotification::class, + [ + 'storeManager' => $this->storeManagerMock, + 'urlBuilder' => $this->urlBuilderMock, + 'taxConfig' => $this->taxConfigMock, + ] + ); + } + + public function testIsDisplayed() + { + $this->taxConfigMock->expects($this->any())->method('applyTaxAfterDiscount')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('isWrongDiscountSettingsIgnored')->willReturn(false); + $this->assertTrue($this->discountErrorsNotification->isDisplayed()); + } + + public function testIsDisplayedIgnoreWrongConfiguration() + { + $this->taxConfigMock->expects($this->any())->method('applyTaxAfterDiscount')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('isWrongDiscountSettingsIgnored')->willReturn(true); + $this->assertFalse($this->discountErrorsNotification->isDisplayed()); + } + + public function testGetText() + { + $this->taxConfigMock->expects($this->any())->method('applyTaxAfterDiscount')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('isWrongDiscountSettingsIgnored')->willReturn(false); + $this->urlBuilderMock->expects($this->any()) + ->method('getUrl') + ->with('tax/tax/ignoreTaxNotification', ['section' => 'discount']) + ->willReturn('http://example.com'); + $this->discountErrorsNotification->isDisplayed(); + $this->assertEquals( + 'With customer tax applied “Before Discount”, the final discount calculation may not match ' + . 'customers’ expectations.

    Store(s) affected: testWebsiteName (testStoreName)' + . '

    Click on the link to ignore this notification

    ', + $this->discountErrorsNotification->getText() + ); + } +} diff --git a/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/RoundingErrorsTest.php b/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/RoundingErrorsTest.php new file mode 100644 index 0000000000000..9b8d0e2922fc8 --- /dev/null +++ b/app/code/Magento/Tax/Test/Unit/Model/System/Message/Notification/RoundingErrorsTest.php @@ -0,0 +1,142 @@ +getMock(WebsiteInterface::class, [], [], '', false); + $websiteMock->expects($this->any())->method('getName')->willReturn('testWebsiteName'); + $storeMock = $this->getMockForAbstractClass( + StoreInterface::class, + [], + '', + false, + true, + true, + ['getWebsite', 'getName'] + ); + $storeMock->expects($this->any())->method('getName')->willReturn('testStoreName'); + $storeMock->expects($this->any())->method('getWebsite')->willReturn($websiteMock); + $this->storeManagerMock = $this->getMock(StoreManagerInterface::class, [], [], '', false); + $this->storeManagerMock->expects($this->any())->method('getStores')->willReturn([$storeMock]); + + $this->urlBuilderMock = $this->getMock(UrlInterface::class, [], [], '', false); + $this->taxConfigMock = $this->getMock(TaxConfig::class, [], [], '', false); + $this->roundingErrorsNotification = (new ObjectManager($this))->getObject( + RoundingErrorsNotification::class, + [ + 'storeManager' => $this->storeManagerMock, + 'urlBuilder' => $this->urlBuilderMock, + 'taxConfig' => $this->taxConfigMock, + ] + ); + } + + public function testIsDisplayedNotDisplayedUnitBased() + { + $this->taxConfigMock->expects($this->any())->method('isWrongDisplaySettingsIgnored')->willReturn(false); + + $this->taxConfigMock->expects($this->any()) + ->method('getAlgorithm')->willReturn(\Magento\Tax\Model\Calculation::CALC_UNIT_BASE); + + $this->taxConfigMock->expects($this->any()) + ->method('getPriceDisplayType')->willReturn(\Magento\Tax\Model\Config::DISPLAY_TYPE_EXCLUDING_TAX); + $this->taxConfigMock->expects($this->any()) + ->method('getShippingPriceDisplayType')->willReturn(\Magento\Tax\Model\Config::DISPLAY_TYPE_EXCLUDING_TAX); + + $this->taxConfigMock->expects($this->any())->method('displayCartPricesBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displayCartSubtotalBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displayCartShippingBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displaySalesPricesBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displaySalesSubtotalBoth')->willReturn(false); + + $this->taxConfigMock->expects($this->any())->method('displaySalesShippingBoth')->willReturn(true); + + $this->assertFalse($this->roundingErrorsNotification->isDisplayed()); + } + + public function testIsDisplayedNotDisplayed() + { + $this->taxConfigMock->expects($this->any())->method('isWrongDisplaySettingsIgnored')->willReturn(false); + + $this->taxConfigMock->expects($this->any()) + ->method('getAlgorithm')->willReturn(\Magento\Tax\Model\Calculation::CALC_ROW_BASE); + + $this->taxConfigMock->expects($this->any()) + ->method('getPriceDisplayType')->willReturn(\Magento\Tax\Model\Config::DISPLAY_TYPE_EXCLUDING_TAX); + $this->taxConfigMock->expects($this->any()) + ->method('getShippingPriceDisplayType')->willReturn(\Magento\Tax\Model\Config::DISPLAY_TYPE_EXCLUDING_TAX); + + $this->taxConfigMock->expects($this->any())->method('displayCartPricesBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displayCartSubtotalBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displayCartShippingBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displaySalesPricesBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displaySalesSubtotalBoth')->willReturn(false); + $this->taxConfigMock->expects($this->any())->method('displaySalesShippingBoth')->willReturn(false); + + $this->assertFalse($this->roundingErrorsNotification->isDisplayed()); + } + + public function testIsDisplayedIgnoreWrongConfiguration() + { + $this->taxConfigMock->expects($this->any())->method('isWrongDisplaySettingsIgnored')->willReturn(true); + $this->assertFalse($this->roundingErrorsNotification->isDisplayed()); + } + + public function testGetText() + { + $this->taxConfigMock->expects($this->any())->method('isWrongDisplaySettingsIgnored')->willReturn(false); + + $this->taxConfigMock->expects($this->any())->method('displaySalesShippingBoth')->willReturn(true); + + $this->urlBuilderMock->expects($this->any()) + ->method('getUrl') + ->with('tax/tax/ignoreTaxNotification', ['section' => 'price_display']) + ->willReturn('http://example.com'); + $this->roundingErrorsNotification->isDisplayed(); + $this->assertEquals( + 'Your current tax configuration may result in rounding errors. ' + . '

    Store(s) affected: testWebsiteName (testStoreName)

    Click on the link to ' + . 'ignore this notification

    ', + $this->roundingErrorsNotification->getText() + ); + } +} diff --git a/app/code/Magento/Tax/Test/Unit/Model/System/Message/NotificationsTest.php b/app/code/Magento/Tax/Test/Unit/Model/System/Message/NotificationsTest.php new file mode 100644 index 0000000000000..cd8392ec85c35 --- /dev/null +++ b/app/code/Magento/Tax/Test/Unit/Model/System/Message/NotificationsTest.php @@ -0,0 +1,97 @@ +storeManagerMock = $this->getMock(StoreManagerInterface::class, [], [], '', false); + $this->urlBuilderMock = $this->getMock(UrlInterface::class, [], [], '', false); + $this->taxConfigMock = $this->getMock(TaxConfig::class, [], [], '', false); + $this->notificationMock = $this->getMock(NotificationInterface::class, [], [], '', false); + $this->notifications = (new ObjectManager($this))->getObject( + Notifications::class, + [ + 'storeManager' => $this->storeManagerMock, + 'urlBuilder' => $this->urlBuilderMock, + 'taxConfig' => $this->taxConfigMock, + 'notifications' => [$this->notificationMock] + ] + ); + } + + /** + * @dataProvider dataProviderIsDisplayed + */ + public function testIsDisplayed( + $isNotificationDisplayed, + $expectedResult + ) { + $this->notificationMock->expects($this->once())->method('isDisplayed')->willReturn($isNotificationDisplayed); + $this->assertEquals($expectedResult, $this->notifications->isDisplayed()); + } + + public function dataProviderIsDisplayed() + { + return [ + [true, true], + [false, false] + ]; + } + + public function testGetText() + { + $this->notificationMock->expects($this->once())->method('getText')->willReturn('Notification Text.'); + $this->taxConfigMock->expects($this->once())->method('getInfoUrl')->willReturn('http://info-url'); + $this->urlBuilderMock->expects($this->once())->method('getUrl') + ->with('adminhtml/system_config/edit/section/tax')->willReturn('http://tax-config-url'); + + $this->assertEquals( + 'Notification Text.

    Please see documentation for more details. ' + . 'Click here to go to Tax Configuration and change your settings.

    ', + $this->notifications->getText() + ); + } +} diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php index 6d468c686e0bc..f32b3cfcda0ab 100644 --- a/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php +++ b/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/adminhtml/di.xml b/app/code/Magento/Tax/etc/adminhtml/di.xml index 120c6f9054e16..16cb3a15ae84e 100644 --- a/app/code/Magento/Tax/etc/adminhtml/di.xml +++ b/app/code/Magento/Tax/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ @@ -13,4 +13,13 @@ + + + + Magento\Tax\Model\System\Message\Notification\RoundingErrors + Magento\Tax\Model\System\Message\Notification\DiscountErrors + Magento\Tax\Model\System\Message\Notification\ApplyDiscountOnPrices + + + diff --git a/app/code/Magento/Tax/etc/adminhtml/menu.xml b/app/code/Magento/Tax/etc/adminhtml/menu.xml index 601f419cfef2e..624aef2e7fa05 100644 --- a/app/code/Magento/Tax/etc/adminhtml/menu.xml +++ b/app/code/Magento/Tax/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/adminhtml/routes.xml b/app/code/Magento/Tax/etc/adminhtml/routes.xml index 3e9c02010090a..531019d5f333d 100644 --- a/app/code/Magento/Tax/etc/adminhtml/routes.xml +++ b/app/code/Magento/Tax/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Tax/etc/adminhtml/system.xml b/app/code/Magento/Tax/etc/adminhtml/system.xml index 87b553dbba57a..bcc132b6a964b 100644 --- a/app/code/Magento/Tax/etc/adminhtml/system.xml +++ b/app/code/Magento/Tax/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ @@ -60,7 +60,7 @@ Magento\Tax\Model\System\Config\Source\PriceType Magento\Tax\Model\Config\Notification - Apply discount on price including tax is calculated based on store tax if "Apply Tax after Discount" is selected. + Warning: To apply the discount on prices including tax and apply the tax after discount, set Catalog Prices to “Including Tax”. diff --git a/app/code/Magento/Tax/etc/catalog_attributes.xml b/app/code/Magento/Tax/etc/catalog_attributes.xml index 932edde556464..9628274563d2b 100644 --- a/app/code/Magento/Tax/etc/catalog_attributes.xml +++ b/app/code/Magento/Tax/etc/catalog_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/config.xml b/app/code/Magento/Tax/etc/config.xml index 0bf9428b7b582..2346b1e6b6d56 100644 --- a/app/code/Magento/Tax/etc/config.xml +++ b/app/code/Magento/Tax/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/crontab.xml b/app/code/Magento/Tax/etc/crontab.xml index ada862a7184b5..1060c426cb2e6 100644 --- a/app/code/Magento/Tax/etc/crontab.xml +++ b/app/code/Magento/Tax/etc/crontab.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/di.xml b/app/code/Magento/Tax/etc/di.xml index 8112720403149..336ef019f7c8c 100644 --- a/app/code/Magento/Tax/etc/di.xml +++ b/app/code/Magento/Tax/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/events.xml b/app/code/Magento/Tax/etc/events.xml index 0fcfbdb2b9525..6d4a4ff94ae61 100644 --- a/app/code/Magento/Tax/etc/events.xml +++ b/app/code/Magento/Tax/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/extension_attributes.xml b/app/code/Magento/Tax/etc/extension_attributes.xml index 488da4b2efc48..61c5eefcd6268 100644 --- a/app/code/Magento/Tax/etc/extension_attributes.xml +++ b/app/code/Magento/Tax/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/fieldset.xml b/app/code/Magento/Tax/etc/fieldset.xml index 97495eb4fa842..37ec0cd6c577a 100644 --- a/app/code/Magento/Tax/etc/fieldset.xml +++ b/app/code/Magento/Tax/etc/fieldset.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/frontend/di.xml b/app/code/Magento/Tax/etc/frontend/di.xml index d7e3b6efe7283..a7b1c766c72f7 100644 --- a/app/code/Magento/Tax/etc/frontend/di.xml +++ b/app/code/Magento/Tax/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/frontend/events.xml b/app/code/Magento/Tax/etc/frontend/events.xml index ad8b2e1844145..206edaf93c7d2 100644 --- a/app/code/Magento/Tax/etc/frontend/events.xml +++ b/app/code/Magento/Tax/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/module.xml b/app/code/Magento/Tax/etc/module.xml index 3094aa2a11723..b816eec92ce0f 100644 --- a/app/code/Magento/Tax/etc/module.xml +++ b/app/code/Magento/Tax/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/pdf.xml b/app/code/Magento/Tax/etc/pdf.xml index 9deba5e82727b..a06265d4782d9 100644 --- a/app/code/Magento/Tax/etc/pdf.xml +++ b/app/code/Magento/Tax/etc/pdf.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/sales.xml b/app/code/Magento/Tax/etc/sales.xml index 8b283fa335729..3d437252cbd17 100644 --- a/app/code/Magento/Tax/etc/sales.xml +++ b/app/code/Magento/Tax/etc/sales.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/etc/webapi.xml b/app/code/Magento/Tax/etc/webapi.xml index 87dce6fc4e665..a67bc2dcb4123 100644 --- a/app/code/Magento/Tax/etc/webapi.xml +++ b/app/code/Magento/Tax/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/registration.php b/app/code/Magento/Tax/registration.php index 7bf35ebbe6617..7e5d1ea05d9cb 100644 --- a/app/code/Magento/Tax/registration.php +++ b/app/code/Magento/Tax/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/sales_invoice_item_price.xml b/app/code/Magento/Tax/view/adminhtml/layout/sales_invoice_item_price.xml index fb62d5fd05d99..3d7663f8536fa 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/sales_invoice_item_price.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/sales_invoice_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/sales_order_create_item_price.xml b/app/code/Magento/Tax/view/adminhtml/layout/sales_order_create_item_price.xml index c69ccec0bb501..375b300e46892 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/sales_order_create_item_price.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/sales_order_create_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/sales_order_item_price.xml b/app/code/Magento/Tax/view/adminhtml/layout/sales_order_item_price.xml index 7d213aca53bf4..9d2fce3b7652f 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/sales_order_item_price.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/sales_order_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_block.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_block.xml index 4d33b0ad065bb..d900a7c957054 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_block.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportcsv.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportcsv.xml index 75aff061bb235..89c857f569f4c 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportcsv.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportcsv.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportxml.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportxml.xml index 75aff061bb235..89c857f569f4c 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportxml.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_exportxml.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_index.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_index.xml index cbf1a995756a6..270004a498ba1 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_index.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rate_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml index 72979563ac462..4a58a9894f43e 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml index 25e59aaf78701..0a9e6e3c59b3b 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_index.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_index.xml index 56d94615ce868..83a60910ae318 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_index.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/templates/class/page/edit.phtml b/app/code/Magento/Tax/view/adminhtml/templates/class/page/edit.phtml index 92e57f57c8a9a..23bcbfbb4340e 100644 --- a/app/code/Magento/Tax/view/adminhtml/templates/class/page/edit.phtml +++ b/app/code/Magento/Tax/view/adminhtml/templates/class/page/edit.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/templates/items/price/row.phtml b/app/code/Magento/Tax/view/adminhtml/templates/items/price/row.phtml index 55c24a6417145..cba78caa5b2e6 100644 --- a/app/code/Magento/Tax/view/adminhtml/templates/items/price/row.phtml +++ b/app/code/Magento/Tax/view/adminhtml/templates/items/price/row.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/templates/toolbar/class/save.phtml b/app/code/Magento/Tax/view/adminhtml/templates/toolbar/class/save.phtml index 1701323e53224..23068fd57de63 100644 --- a/app/code/Magento/Tax/view/adminhtml/templates/toolbar/class/save.phtml +++ b/app/code/Magento/Tax/view/adminhtml/templates/toolbar/class/save.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/adminhtml/templates/toolbar/rule/save.phtml b/app/code/Magento/Tax/view/adminhtml/templates/toolbar/rule/save.phtml index 1dcc47c92436e..baa5f257ea7ac 100644 --- a/app/code/Magento/Tax/view/adminhtml/templates/toolbar/rule/save.phtml +++ b/app/code/Magento/Tax/view/adminhtml/templates/toolbar/rule/save.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/base/templates/pricing/adjustment.phtml b/app/code/Magento/Tax/view/base/templates/pricing/adjustment.phtml index 20b8d0959f596..e3a765984d6ad 100644 --- a/app/code/Magento/Tax/view/base/templates/pricing/adjustment.phtml +++ b/app/code/Magento/Tax/view/base/templates/pricing/adjustment.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml b/app/code/Magento/Tax/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml index 0db666f4b60b8..93baddd73a9d3 100644 --- a/app/code/Magento/Tax/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml +++ b/app/code/Magento/Tax/view/frontend/layout/checkout_cart_sidebar_total_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Tax/view/frontend/layout/checkout_index_index.xml index 03ba3dd94a8e0..f8eeca47a1376 100644 --- a/app/code/Magento/Tax/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Tax/view/frontend/layout/checkout_index_index.xml @@ -1,7 +1,7 @@ @@ -98,4 +98,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Tax/view/frontend/layout/checkout_item_price_renderers.xml b/app/code/Magento/Tax/view/frontend/layout/checkout_item_price_renderers.xml index ceb66a40b8f3e..5665eb0b5cd43 100644 --- a/app/code/Magento/Tax/view/frontend/layout/checkout_item_price_renderers.xml +++ b/app/code/Magento/Tax/view/frontend/layout/checkout_item_price_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/frontend/layout/sales_email_item_price.xml b/app/code/Magento/Tax/view/frontend/layout/sales_email_item_price.xml index 1788e2e60985a..0ef199db11b4d 100644 --- a/app/code/Magento/Tax/view/frontend/layout/sales_email_item_price.xml +++ b/app/code/Magento/Tax/view/frontend/layout/sales_email_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/frontend/layout/sales_order_item_price.xml b/app/code/Magento/Tax/view/frontend/layout/sales_order_item_price.xml index 36d47f7ccc590..acfb68b9c0de4 100644 --- a/app/code/Magento/Tax/view/frontend/layout/sales_order_item_price.xml +++ b/app/code/Magento/Tax/view/frontend/layout/sales_order_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Tax/view/frontend/templates/checkout/cart/item/price/sidebar.phtml b/app/code/Magento/Tax/view/frontend/templates/checkout/cart/item/price/sidebar.phtml index 814cebbc01548..9d1a1d40763da 100644 --- a/app/code/Magento/Tax/view/frontend/templates/checkout/cart/item/price/sidebar.phtml +++ b/app/code/Magento/Tax/view/frontend/templates/checkout/cart/item/price/sidebar.phtml @@ -1,6 +1,6 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Tax/view/frontend/templates/checkout/shipping/price.phtml b/app/code/Magento/Tax/view/frontend/templates/checkout/shipping/price.phtml index b40f55b07cf43..e289976f5981f 100644 --- a/app/code/Magento/Tax/view/frontend/templates/checkout/shipping/price.phtml +++ b/app/code/Magento/Tax/view/frontend/templates/checkout/shipping/price.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/shipping.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/shipping.html index 42555380fbd25..afbe285629b24 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/shipping.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/shipping.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/tax.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/tax.html index 162b86a395ff1..738a0125da02f 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/tax.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/cart/totals/tax.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/minicart/subtotal/totals.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/minicart/subtotal/totals.html index 24d4bd41bbd0e..eb20767de779e 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/minicart/subtotal/totals.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/minicart/subtotal/totals.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html index 66ce615585d13..9b0077c3d4b11 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/shipping_method/price.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/grand-total.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/grand-total.html index 059c79fbca120..0dd86baae2ebf 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/grand-total.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/grand-total.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/item/details/subtotal.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/item/details/subtotal.html index d573308288e6c..60778bdba2117 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/item/details/subtotal.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/item/details/subtotal.html @@ -1,6 +1,6 @@ @@ -31,4 +31,4 @@ -
    \ No newline at end of file +
    diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/shipping.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/shipping.html index f722bde43828b..ff4acc3ed5b49 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/shipping.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/shipping.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/subtotal.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/subtotal.html index ddfbac7f3dd9c..9da9955d45f90 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/subtotal.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/subtotal.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/tax.html b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/tax.html index 47c386892273b..68ccf75c6015d 100644 --- a/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/tax.html +++ b/app/code/Magento/Tax/view/frontend/web/template/checkout/summary/tax.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/TaxImportExport/Block/Adminhtml/Rate/Grid/Renderer/Country.php b/app/code/Magento/TaxImportExport/Block/Adminhtml/Rate/Grid/Renderer/Country.php index 8f79da385e618..da9b250e91149 100644 --- a/app/code/Magento/TaxImportExport/Block/Adminhtml/Rate/Grid/Renderer/Country.php +++ b/app/code/Magento/TaxImportExport/Block/Adminhtml/Rate/Grid/Renderer/Country.php @@ -1,6 +1,6 @@ toString($template) . "\n"; } - return $this->fileFactory->create(\tax_rates.csv::class, $content, DirectoryList::VAR_DIR); + return $this->fileFactory->create('tax_rates.csv', $content, DirectoryList::VAR_DIR); } /** diff --git a/app/code/Magento/TaxImportExport/Controller/Adminhtml/Rate/ExportXml.php b/app/code/Magento/TaxImportExport/Controller/Adminhtml/Rate/ExportXml.php index 47ac271b9d6b6..ca781d267518f 100644 --- a/app/code/Magento/TaxImportExport/Controller/Adminhtml/Rate/ExportXml.php +++ b/app/code/Magento/TaxImportExport/Controller/Adminhtml/Rate/ExportXml.php @@ -1,6 +1,6 @@ objectManagerHelper = new ObjectManagerHelper($this); + $this->fileFactoryMock = $this->getMock( + \Magento\Framework\App\Response\Http\FileFactory::class, + [], + [], + '', + false + ); + $this->objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); + $this->controller = $this->objectManagerHelper->getObject( + \Magento\TaxImportExport\Controller\Adminhtml\Rate\ExportPost::class, + [ + 'fileFactory' => $this->fileFactoryMock, + 'objectManager' => $this->objectManagerMock + ] + ); + } + + public function testExecute() + { + $headers = new \Magento\Framework\DataObject( + [ + 'code' => __('Code'), + 'country_name' => __('Country'), + 'region_name' => __('State'), + 'tax_postcode' => __('Zip/Post Code'), + 'rate' => __('Rate'), + 'zip_is_range' => __('Zip/Post is Range'), + 'zip_from' => __('Range From'), + 'zip_to' => __('Range To'), + ] + ); + $template = '"{{code}}","{{country_name}}","{{region_name}}","{{tax_postcode}}","{{rate}}"' . + ',"{{zip_is_range}}","{{zip_from}}","{{zip_to}}"'; + $content = $headers->toString($template); + $content .= "\n"; + $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $storeCollectionMock = $this->objectManagerHelper->getCollectionMock( + \Magento\Store\Model\ResourceModel\Store\Collection::class, + [] + ); + $rateCollectionMock = $this->objectManagerHelper->getCollectionMock( + \Magento\Tax\Model\ResourceModel\Calculation\Rate\Collection::class, + [] + ); + + $taxCollectionMock = $this->objectManagerHelper->getCollectionMock( + \Magento\Tax\Model\ResourceModel\Calculation\Rate\Title\Collection::class, + [] + ); + $storeCollectionMock->expects($this->once())->method('setLoadDefault')->willReturnSelf(); + $rateTitleMock = $this->getMock(\Magento\Tax\Model\Calculation\Rate\Title::class, [], [], '', false); + $rateTitleMock->expects($this->once())->method('getCollection')->willReturn($taxCollectionMock); + $storeMock->expects($this->once())->method('getCollection')->willReturn($storeCollectionMock); + $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap([ + [\Magento\Store\Model\Store::class, [], $storeMock], + [\Magento\Tax\Model\Calculation\Rate\Title::class, [], $rateTitleMock], + [\Magento\Tax\Model\ResourceModel\Calculation\Rate\Collection::class, [], $rateCollectionMock] + ]); + $rateCollectionMock->expects($this->once())->method('joinCountryTable')->willReturnSelf(); + $rateCollectionMock->expects($this->once())->method('joinRegionTable')->willReturnSelf(); + $this->fileFactoryMock + ->expects($this->once()) + ->method('create') + ->with('tax_rates.csv', $content, DirectoryList::VAR_DIR); + $this->controller->execute(); + } +} diff --git a/app/code/Magento/TaxImportExport/composer.json b/app/code/Magento/TaxImportExport/composer.json index c3d09e4926e02..9d9cac5dec59c 100644 --- a/app/code/Magento/TaxImportExport/composer.json +++ b/app/code/Magento/TaxImportExport/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-tax-import-export", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/module-tax": "100.2.*", "magento/module-backend": "100.2.*", "magento/module-directory": "100.2.*", diff --git a/app/code/Magento/TaxImportExport/etc/acl.xml b/app/code/Magento/TaxImportExport/etc/acl.xml index 140c53d2f3e82..2cb522b1aa57d 100644 --- a/app/code/Magento/TaxImportExport/etc/acl.xml +++ b/app/code/Magento/TaxImportExport/etc/acl.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/TaxImportExport/etc/adminhtml/menu.xml b/app/code/Magento/TaxImportExport/etc/adminhtml/menu.xml index 648752d188a8d..c6793683a4829 100644 --- a/app/code/Magento/TaxImportExport/etc/adminhtml/menu.xml +++ b/app/code/Magento/TaxImportExport/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/TaxImportExport/etc/adminhtml/routes.xml b/app/code/Magento/TaxImportExport/etc/adminhtml/routes.xml index 5485351813bec..566345bc2e90d 100644 --- a/app/code/Magento/TaxImportExport/etc/adminhtml/routes.xml +++ b/app/code/Magento/TaxImportExport/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/TaxImportExport/etc/module.xml b/app/code/Magento/TaxImportExport/etc/module.xml index a3128279232dd..931ebe9845a71 100644 --- a/app/code/Magento/TaxImportExport/etc/module.xml +++ b/app/code/Magento/TaxImportExport/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/TaxImportExport/registration.php b/app/code/Magento/TaxImportExport/registration.php index f00708bf0152f..c187a78c0d7b4 100644 --- a/app/code/Magento/TaxImportExport/registration.php +++ b/app/code/Magento/TaxImportExport/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/TaxImportExport/view/adminhtml/layout/tax_rule_edit.xml b/app/code/Magento/TaxImportExport/view/adminhtml/layout/tax_rule_edit.xml index c8f7e6f1fa87c..b8c36c9d4282c 100644 --- a/app/code/Magento/TaxImportExport/view/adminhtml/layout/tax_rule_edit.xml +++ b/app/code/Magento/TaxImportExport/view/adminhtml/layout/tax_rule_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/TaxImportExport/view/adminhtml/templates/importExport.phtml b/app/code/Magento/TaxImportExport/view/adminhtml/templates/importExport.phtml index e7ba46e851da5..12f48c00fda16 100644 --- a/app/code/Magento/TaxImportExport/view/adminhtml/templates/importExport.phtml +++ b/app/code/Magento/TaxImportExport/view/adminhtml/templates/importExport.phtml @@ -1,6 +1,6 @@ _menu = $nodeFactory->create( - [ - 'data' => [], - 'idField' => 'root', - 'tree' => $treeFactory->create() - ] - ); + $this->nodeFactory = $nodeFactory; + $this->treeFactory = $treeFactory; } /** @@ -81,18 +88,18 @@ public function getHtml($outermostClass = '', $childrenWrapClass = '', $limit = { $this->_eventManager->dispatch( 'page_block_html_topmenu_gethtml_before', - ['menu' => $this->_menu, 'block' => $this] + ['menu' => $this->getMenu(), 'block' => $this, 'request' => $this->getRequest()] ); - $this->_menu->setOutermostClass($outermostClass); - $this->_menu->setChildrenWrapClass($childrenWrapClass); + $this->getMenu()->setOutermostClass($outermostClass); + $this->getMenu()->setChildrenWrapClass($childrenWrapClass); - $html = $this->_getHtml($this->_menu, $childrenWrapClass, $limit); + $html = $this->_getHtml($this->getMenu(), $childrenWrapClass, $limit); $transportObject = new \Magento\Framework\DataObject(['html' => $html]); $this->_eventManager->dispatch( 'page_block_html_topmenu_gethtml_after', - ['menu' => $this->_menu, 'transportObject' => $transportObject] + ['menu' => $this->getMenu(), 'transportObject' => $transportObject] ); $html = $transportObject->getHtml(); return $html; @@ -370,10 +377,22 @@ protected function getCacheTags() /** * Get menu object. * + * Creates \Magento\Framework\Data\Tree\Node root node object. + * The creation logic was moved from class constructor into separate method. + * * @return Node */ public function getMenu() { + if (!$this->_menu) { + $this->_menu = $this->nodeFactory->create( + [ + 'data' => [], + 'idField' => 'root', + 'tree' => $this->treeFactory->create() + ] + ); + } return $this->_menu; } } diff --git a/app/code/Magento/Theme/Block/Html/Welcome.php b/app/code/Magento/Theme/Block/Html/Welcome.php index 8f141043ee11d..96910bd2c7bc8 100644 --- a/app/code/Magento/Theme/Block/Html/Welcome.php +++ b/app/code/Magento/Theme/Block/Html/Welcome.php @@ -1,6 +1,6 @@ setCookie($this->getMessages()); + } + return $result; + } + + /** + * Set 'mage-messages' cookie with 'messages' array + * + * Checks the $messages argument. If $messages is not an empty array, then + * sets 'mage-messages' public cookie: + * + * Cookie Name: 'mage-messages'; + * Cookie Duration: 1 year; + * Cookie Path: /; + * Cookie HTTP Only flag: FALSE. Cookie can be accessed by client-side APIs. + * + * The 'messages' list has format: + * [ + * [ + * 'type' => 'type_value', + * 'text' => 'cookie_value', + * ], + * ] + * + * + * @param array $messages List of Magento messages that must be set as 'mage-messages' cookie. + * @return void + */ + private function setCookie(array $messages) + { + if (!empty($messages)) { $publicCookieMetadata = $this->cookieMetadataFactory->createPublicCookieMetadata(); $publicCookieMetadata->setDurationOneYear(); $publicCookieMetadata->setPath('/'); $publicCookieMetadata->setHttpOnly(false); + $this->cookieManager->setPublicCookie( self::MESSAGES_COOKIES_NAME, - $this->jsonHelper->jsonEncode($this->getMessages()), + $this->jsonHelper->jsonEncode($messages), $publicCookieMetadata ); } - - return $result; } /** diff --git a/app/code/Magento/Theme/CustomerData/Messages.php b/app/code/Magento/Theme/CustomerData/Messages.php index ab9411f131ca8..b1dffcb5ae514 100644 --- a/app/code/Magento/Theme/CustomerData/Messages.php +++ b/app/code/Magento/Theme/CustomerData/Messages.php @@ -1,6 +1,6 @@ _localeDate = $localeDate; $this->_dateTime = $dateTime; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); parent::__construct($context, $registry, $resource, $resourceCollection, $data); } @@ -108,9 +118,9 @@ public function loadChange($storeId, $date = null) if (!$result) { $result = []; } - $this->_cacheManager->save(serialize($result), $changeCacheId, [self::CACHE_TAG], 86400); + $this->_cacheManager->save($this->serializer->serialize($result), $changeCacheId, [self::CACHE_TAG], 86400); } else { - $result = unserialize($result); + $result = $this->serializer->unserialize($result); } if ($result) { diff --git a/app/code/Magento/Theme/Model/Design/Backend/Exceptions.php b/app/code/Magento/Theme/Model/Design/Backend/Exceptions.php index 1e0e44bad1ca4..7be65602ee061 100644 --- a/app/code/Magento/Theme/Model/Design/Backend/Exceptions.php +++ b/app/code/Magento/Theme/Model/Design/Backend/Exceptions.php @@ -1,11 +1,12 @@ _design = $design; - parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + parent::__construct( + $context, + $registry, + $config, + $cacheTypeList, + $resource, + $resourceCollection, + $data, + $serializer + ); } /** diff --git a/app/code/Magento/Theme/Model/Design/Backend/Favicon.php b/app/code/Magento/Theme/Model/Design/Backend/Favicon.php index ebab873f99f60..fce2b35a7f57e 100644 --- a/app/code/Magento/Theme/Model/Design/Backend/Favicon.php +++ b/app/code/Magento/Theme/Model/Design/Backend/Favicon.php @@ -1,6 +1,6 @@ $url, 'file' => $value, 'size' => is_array($stat) ? $stat['size'] : 0, - 'exists' => true + 'name' => basename($value), + 'type' => $this->getMimeType($fileName), + 'exists' => true, ] ]; } @@ -192,4 +201,33 @@ protected function getTmpMediaPath($filename) { return 'tmp/' . FileProcessor::FILE_DIR . '/' . $filename; } + + /** + * Retrieve MIME type of requested file + * + * @param string $fileName + * @return string + */ + private function getMimeType($fileName) + { + $absoluteFilePath = $this->_mediaDirectory->getAbsolutePath($fileName); + + $result = $this->getMime()->getMimeType($absoluteFilePath); + return $result; + } + + /** + * Get Mime instance + * + * @return Mime + * + * @deprecated + */ + private function getMime() + { + if ($this->mime === null) { + $this->mime = ObjectManager::getInstance()->get(Mime::class); + } + return $this->mime; + } } diff --git a/app/code/Magento/Theme/Model/Design/Backend/Image.php b/app/code/Magento/Theme/Model/Design/Backend/Image.php index f9e80b921fd13..8aa2742dda9b7 100644 --- a/app/code/Magento/Theme/Model/Design/Backend/Image.php +++ b/app/code/Magento/Theme/Model/Design/Backend/Image.php @@ -1,6 +1,6 @@ loadedData = $this->dataLoader->getData(); return $this->loadedData; } + + /** + * {@inheritdoc} + */ + public function getMeta() + { + $meta = parent::getMeta(); + if (!isset($meta['other_settings']['children'])) { + return $meta; + } + + $request = $this->getRequest()->getParams(); + if (!isset($request['scope'])) { + return $meta; + } + + $scope = $request['scope']; + $scopeCode = $this->getScopeCodeResolver()->resolve( + $scope, + isset($request['scope_id']) ? $request['scope_id'] : null + ); + + foreach ($meta['other_settings']['children'] as $settingGroupName => &$settingGroup) { + foreach ($settingGroup['children'] as $fieldName => &$field) { + $path = sprintf( + 'design/%s/%s', + $settingGroupName, + preg_replace('/^' . $settingGroupName . '_/', '', $fieldName) + ); + $isReadOnly = $this->getSettingChecker()->isReadOnly( + $path, + $scope, + $scopeCode + ); + + if ($isReadOnly) { + $field['arguments']['data']['config']['disabled'] = true; + $field['arguments']['data']['config']['is_disable_inheritance'] = true; + } + } + } + + return $meta; + } + + /** + * @deprecated + * @return ScopeCodeResolver + */ + private function getScopeCodeResolver() + { + if ($this->scopeCodeResolver === null) { + $this->scopeCodeResolver = ObjectManager::getInstance()->get(ScopeCodeResolver::class); + } + return $this->scopeCodeResolver; + } + + /** + * @deprecated + * @return SettingChecker + */ + private function getSettingChecker() + { + if ($this->settingChecker === null) { + $this->settingChecker = ObjectManager::getInstance()->get(SettingChecker::class); + } + return $this->settingChecker; + } + + /** + * @deprecated + * @return RequestInterface + */ + private function getRequest() + { + if ($this->request === null) { + $this->request = ObjectManager::getInstance()->get(RequestInterface::class); + } + return $this->request; + } } diff --git a/app/code/Magento/Theme/Model/Design/Config/DataProvider/DataLoader.php b/app/code/Magento/Theme/Model/Design/Config/DataProvider/DataLoader.php index d2362cd8735a1..461003b612e0f 100644 --- a/app/code/Magento/Theme/Model/Design/Config/DataProvider/DataLoader.php +++ b/app/code/Magento/Theme/Model/Design/Config/DataProvider/DataLoader.php @@ -1,6 +1,6 @@ '', 'size' => '']; /** @var File $backendModel */ $backendModel = $this->getBackendModel($fileId); $uploader = $this->uploaderFactory->create(['fileId' => $fileId]); @@ -143,7 +142,9 @@ protected function save($fileId, $destination) $uploader->setFilesDispersion(false); $uploader->setAllowedExtensions($backendModel->getAllowedExtensions()); $uploader->addValidateCallback('size', $backendModel, 'validateMaxSize'); - return array_intersect_key($uploader->save($destination), $result); + + $result = $uploader->save($destination); + return $result; } /** diff --git a/app/code/Magento/Theme/Model/Design/Config/MetadataProvider.php b/app/code/Magento/Theme/Model/Design/Config/MetadataProvider.php index e312a80aef1d5..67b50f8d01ce7 100644 --- a/app/code/Magento/Theme/Model/Design/Config/MetadataProvider.php +++ b/app/code/Magento/Theme/Model/Design/Config/MetadataProvider.php @@ -1,6 +1,6 @@ deploymentConfig = $deploymentConfig; + $this->themeFactory = $themeFactory; + $this->dataObjectFactory = $dataObjectFactory; + } + + /** + * Retrieves configuration data array. + * Example: + * + * ```php + * ['Magento/backend' => + * [ + * 'parent_id' => NULL, + * 'theme_path' => 'Magento/backend', + * 'theme_title' => 'Magento 2 backend', + * 'is_featured' => '0', + * 'area' => 'adminhtml', + * 'type' => '0', + * 'code' => 'Magento/backend', + * ] + * ] + * ``` + * + * @param string $path The path to theme configuration. + * @return array The data array with theme configurations. + */ + public function get($path = '') + { + if (!$this->deploymentConfig->isDbAvailable()) { + return []; + } + + if (!$this->data) { + $rawThemes = $this->fetchThemes(); + $themes = []; + + foreach ($rawThemes as $themeRow) { + unset($themeRow['theme_id'], $themeRow['preview_image']); + + $themes[$themeRow['code']] = $themeRow; + + if (isset($rawThemes[$themeRow['parent_id']]['code'])) { + $themes[$themeRow['code']]['parent_id'] = $rawThemes[$themeRow['parent_id']]['code']; + } + } + + $this->data = $this->dataObjectFactory->create($themes); + } + + return $this->data->getData($path) ?: []; + } + + /** + * Fetches themes from data source. + * + * @return array An associative list with found themes + */ + private function fetchThemes() + { + /** @var Theme $theme */ + $theme = $this->themeFactory->create(); + $select = $theme->getConnection()->select() + ->from($theme->getMainTable()) + ->order('theme_id'); + + return $theme->getConnection()->fetchAssoc($select); + } +} diff --git a/app/code/Magento/Theme/Model/Theme.php b/app/code/Magento/Theme/Model/Theme.php index 3d386f445301e..2f68cef61e978 100644 --- a/app/code/Magento/Theme/Model/Theme.php +++ b/app/code/Magento/Theme/Model/Theme.php @@ -1,10 +1,11 @@ _themeFactory = $themeFactory; @@ -117,6 +124,7 @@ public function __construct( $this->_imageFactory = $imageFactory; $this->_validator = $validator; $this->_customFactory = $customizationFactory; + $this->themeModelFactory = $themeModelFactory ?: ObjectManager::getInstance()->get(ThemeFactory::class); $this->addData(['type' => self::TYPE_VIRTUAL]); } @@ -377,52 +385,54 @@ public function getInheritedThemes() } /** - * {@inheritdoc} + * @inheritdoc */ - public function __sleep() + public function toArray(array $keys = []) { - $properties = parent::__sleep(); - $key = array_search('_logger', $properties); - if (false !== $key) { - unset($properties[$key]); + $data = parent::toArray($keys); + if (isset($data['parent_theme'])) { + $data['parent_theme'] = $this->getParentTheme()->toArray(); } - return array_diff( - $properties, - [ - '_resource', - '_resourceCollection', - '_themeFactory', - '_domainFactory', - '_imageFactory', - '_validator', - '_customFactory' - ] - ); + + if (isset($data['inherited_themes'])) { + foreach ($data['inherited_themes'] as $key => $inheritedTheme) { + $data['inherited_themes'][$key] = $inheritedTheme->toArray(); + } + } + + return $data; } /** - * {@inheritdoc} + * Populate Theme object from an array + * + * @param array $data + * @return Theme */ - public function __wakeup() + public function populateFromArray(array $data) { - parent::__wakeup(); - $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); - $this->_resource = $objectManager->get(\Magento\Theme\Model\ResourceModel\Theme::class); - $this->_resourceCollection = $objectManager->get(\Magento\Theme\Model\ResourceModel\Theme\Collection::class); - $this->_themeFactory = $objectManager->get(\Magento\Framework\View\Design\Theme\FlyweightFactory::class); - $this->_domainFactory = $objectManager->get(\Magento\Framework\View\Design\Theme\Domain\Factory::class); - $this->_imageFactory = $objectManager->get(\Magento\Framework\View\Design\Theme\ImageFactory::class); - $this->_validator = $objectManager->get(\Magento\Framework\View\Design\Theme\Validator::class); - $this->_customFactory = $objectManager->get(\Magento\Framework\View\Design\Theme\CustomizationFactory::class); + $this->_data = $data; + if (isset($data['parent_theme'])) { + $this->_data['parent_theme'] = $this->createThemeInstance()->populateFromArray($data['parent_theme']); + } + + if (isset($data['inherited_themes'])) { + foreach ($data['inherited_themes'] as $key => $inheritedTheme) { + $themeInstance = $this->createThemeInstance()->populateFromArray($inheritedTheme); + $this->_data['inherited_themes'][$key] = $themeInstance; + } + } + + return $this; } /** - * @param int $modelId - * @param null $field - * @return $this + * Create Theme instance + * + * @return \Magento\Theme\Model\Theme */ - public function load($modelId, $field = null) + private function createThemeInstance() { - return parent::load($modelId, $field); // TODO: Change the autogenerated stub + return $this->themeModelFactory->create(); } } diff --git a/app/code/Magento/Theme/Model/Theme/Collection.php b/app/code/Magento/Theme/Model/Theme/Collection.php index 42690f695ef47..4384ac2dfd262 100644 --- a/app/code/Magento/Theme/Model/Theme/Collection.php +++ b/app/code/Magento/Theme/Model/Theme/Collection.php @@ -1,6 +1,6 @@ collectionFactory = $collectionFactory; $this->themeFactory = $themeFactory; $this->cache = $cache; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); } /** - * {@inheritdoc} + * @inheritdoc */ public function getThemeByFullPath($fullPath) { - /** @var $themeCollection \Magento\Theme\Model\ResourceModel\Theme\Collection */ - $theme = $this->cache->load('theme'. $fullPath); + if (isset($this->themes[$fullPath])) { + return $this->themes[$fullPath]; + } + + if (! $this->getDeploymentConfig()->isDbAvailable()) { + return $this->getThemeList()->getThemeByFullPath($fullPath); + } + + $theme = $this->loadThemeFromCache('theme' . $fullPath); if ($theme) { - return unserialize($theme); + $this->themes[$fullPath] = $theme; + return $theme; } $themeCollection = $this->collectionFactory->create(); - $item = $themeCollection->getThemeByFullPath($fullPath); - if ($item->getId()) { - $themeData = serialize($item); - $this->cache->save($themeData, 'theme' . $fullPath); - $this->cache->save($themeData, 'theme-by-id-' . $item->getId()); + $theme = $themeCollection->getThemeByFullPath($fullPath); + if ($theme->getId()) { + $this->saveThemeToCache($theme, 'theme' . $fullPath); + $this->saveThemeToCache($theme, 'theme-by-id-' . $theme->getId()); + $this->themes[$fullPath] = $theme; } - return $item; + + return $theme; } /** - * {@inheritdoc} + * @inheritdoc */ public function getThemeCustomizations( $area = \Magento\Framework\App\Area::AREA_FRONTEND, @@ -73,20 +113,80 @@ public function getThemeCustomizations( } /** - * {@inheritdoc} + * @inheritdoc */ public function getThemeById($themeId) { - $theme = $this->cache->load('theme-by-id-' . $themeId); + if (isset($this->themes[$themeId])) { + return $this->themes[$themeId]; + } + $theme = $this->loadThemeFromCache('theme-by-id-' . $themeId); if ($theme) { - return unserialize($theme); + $this->themes[$themeId] = $theme; + return $theme; + } + $theme = $this->themeFactory->create(); + $theme->load($themeId); + if ($theme->getId()) { + // We only cache by ID, as virtual themes may share the same path + $this->saveThemeToCache($theme, 'theme-by-id-' . $themeId); + $this->themes[$themeId] = $theme; + } + return $theme; + } + + /** + * Load Theme model from cache + * + * @param string $cacheId + * @return \Magento\Theme\Model\Theme|null + */ + private function loadThemeFromCache($cacheId) + { + $themeData = $this->cache->load($cacheId); + if ($themeData) { + $themeData = $this->serializer->unserialize($themeData); + $theme = $this->themeFactory->create()->populateFromArray($themeData); + return $theme; + } + + return null; + } + + /** + * Save Theme model to the cache + * + * @param \Magento\Theme\Model\Theme $theme + * @param string $cacheId + * @return void + */ + private function saveThemeToCache(\Magento\Theme\Model\Theme $theme, $cacheId) + { + $themeData = $this->serializer->serialize($theme->toArray()); + $this->cache->save($themeData, $cacheId); + } + + /** + * @deprecated + * @return ListInterface + */ + private function getThemeList() + { + if ($this->themeList === null) { + $this->themeList = ObjectManager::getInstance()->get(ListInterface::class); } - /** @var $themeModel \Magento\Framework\View\Design\ThemeInterface */ - $themeModel = $this->themeFactory->create(); - $themeModel->load($themeId); - if ($themeModel->getId()) { - $this->cache->save(serialize($themeModel), 'theme-by-id-' . $themeId); + return $this->themeList; + } + + /** + * @deprecated + * @return DeploymentConfig + */ + private function getDeploymentConfig() + { + if ($this->deploymentConfig === null) { + $this->deploymentConfig = ObjectManager::getInstance()->get(DeploymentConfig::class); } - return $themeModel; + return $this->deploymentConfig; } } diff --git a/app/code/Magento/Theme/Model/Theme/ThemeUninstaller.php b/app/code/Magento/Theme/Model/Theme/ThemeUninstaller.php index 4e450ef218c2e..33d14c030a2ed 100644 --- a/app/code/Magento/Theme/Model/Theme/ThemeUninstaller.php +++ b/app/code/Magento/Theme/Model/Theme/ThemeUninstaller.php @@ -1,6 +1,6 @@ fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; $this->indexerRegistry = $indexerRegistry; } @@ -39,6 +60,38 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $setup->startSetup(); $indexer = $this->indexerRegistry->get(Config::DESIGN_CONFIG_GRID_INDEXER_ID); $indexer->reindexAll(); + if (version_compare($context->getVersion(), '2.0.2', '<')) { + $this->upgradeToVersionTwoZeroTwo($setup); + } $setup->endSetup(); } + + /** + * Upgrade to version 2.0.2, convert data for `value` field in `core_config_data table` + * from php-serialized to JSON format + * + * @param ModuleDataSetupInterface $setup + * @return void + */ + private function upgradeToVersionTwoZeroTwo(ModuleDataSetupInterface $setup) + { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'path' => [ + 'design/theme/ua_regexp', + ] + ] + ] + ); + $fieldDataConverter->convert( + $setup->getConnection(), + $setup->getTable('core_config_data'), + 'config_id', + 'value', + $queryModifier + ); + } } diff --git a/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/BackButtonTest.php b/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/BackButtonTest.php index dabae536fc198..56969686ea703 100644 --- a/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/BackButtonTest.php +++ b/app/code/Magento/Theme/Test/Unit/Block/Adminhtml/Design/Config/Edit/BackButtonTest.php @@ -1,6 +1,6 @@ HTML; - /** - * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $storeManager; - // @codingStandardsIgnoreEnd protected function setUp() { - - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) ->getMockForAbstractClass(); - $this->urlBuilder = $this->getMockBuilder(\Magento\Framework\UrlInterface::class)->getMockForAbstractClass(); + $this->urlBuilder = $this->getMockBuilder(\Magento\Framework\UrlInterface::class) + ->getMockForAbstractClass(); + + $this->eventManagerMock = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class) + ->getMockForAbstractClass(); + + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->getMockForAbstractClass(); + + $this->nodeFactory = $this->getMockBuilder(\Magento\Framework\Data\Tree\NodeFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->treeFactory = $this->getMockBuilder(\Magento\Framework\Data\TreeFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->context = $objectManager->getObject( \Magento\Framework\View\Element\Template\Context::class, - ['urlBuilder' => $this->urlBuilder, 'storeManager' => $this->storeManager] + [ + 'urlBuilder' => $this->urlBuilder, + 'storeManager' => $this->storeManager, + 'eventManager' => $this->eventManagerMock, + 'request' => $this->requestMock, + ] ); - } protected function getTopmenu() @@ -88,14 +116,68 @@ protected function getTopmenu() public function testGetHtmlWithoutSelectedCategory() { - $this->buildTree(false); - $this->assertEquals($this->htmlWithoutCategory, $this->getTopmenu()->getHtml()); + $topmenuBlock = $this->getTopmenu(); + + $treeNode = $this->buildTree(false); + + $transportObject = new \Magento\Framework\DataObject(['html' => $this->htmlWithoutCategory]); + + $this->eventManagerMock->expects($this->exactly(2)) + ->method('dispatch') + ->willReturnMap([ + [ + 'page_block_html_topmenu_gethtml_before', + [ + 'menu' => $treeNode, + 'block' => $topmenuBlock, + 'request' => $this->requestMock, + ], + $this->eventManagerMock + ], + [ + 'page_block_html_topmenu_gethtml_after', + [ + 'menu' => $treeNode, + 'transportObject' => $transportObject, + ], + $this->eventManagerMock + ], + ]); + + $this->assertEquals($this->htmlWithoutCategory, $topmenuBlock->getHtml()); } public function testGetHtmlWithSelectedCategory() { - $this->buildTree(true); - $this->assertEquals($this->htmlWithCategory, $this->getTopmenu()->getHtml()); + $topmenuBlock = $this->getTopmenu(); + + $treeNode = $this->buildTree(true); + + $transportObject = new \Magento\Framework\DataObject(['html' => $this->htmlWithCategory]); + + $this->eventManagerMock->expects($this->exactly(2)) + ->method('dispatch') + ->willReturnMap([ + [ + 'page_block_html_topmenu_gethtml_before', + [ + 'menu' => $treeNode, + 'block' => $topmenuBlock, + 'request' => $this->requestMock, + ], + $this->eventManagerMock + ], + [ + 'page_block_html_topmenu_gethtml_after', + [ + 'menu' => $treeNode, + 'transportObject' => $transportObject, + ], + $this->eventManagerMock + ], + ]); + + $this->assertEquals($this->htmlWithCategory, $topmenuBlock->getHtml()); } public function testGetCacheKeyInfo() @@ -120,15 +202,18 @@ public function testGetCacheKeyInfo() } /** - * @param $isCurrentItem - * @return void + * Create Tree Node mock object + * + * Helper method, that provides unified logic of creation of Tree Node mock objects. + * + * @param bool $isCurrentItem + * @return \PHPUnit_Framework_MockObject_MockObject */ private function buildTree($isCurrentItem) { - $this->nodeFactory = $this->getMock(\Magento\Framework\Data\Tree\NodeFactory::class, [], [], '', false); - $this->treeFactory = $this->getMock(\Magento\Framework\Data\TreeFactory::class, [], [], '', false); - - $tree = $this->getMock(\Magento\Framework\Data\Tree::class, [], [], '', false); + $treeMock = $this->getMockBuilder(\Magento\Framework\Data\Tree::class) + ->disableOriginalConstructor() + ->getMock(); $container = $this->getMock(\Magento\Catalog\Model\ResourceModel\Category\Tree::class, [], [], '', false); @@ -164,12 +249,62 @@ private function buildTree($isCurrentItem) $children->expects($this->once())->method('count')->willReturn(10); - $node = $this->getMock(\Magento\Framework\Data\Tree\Node::class, ['getChildren'], [], '', false); - $node->expects($this->once())->method('getChildren')->willReturn($children); - $node->expects($this->any())->method('__call')->with('getLevel', [])->willReturn(null); + $nodeMock = $this->getMockBuilder(\Magento\Framework\Data\Tree\Node::class) + ->disableOriginalConstructor() + ->setMethods(['getChildren']) + ->getMock(); + $nodeMock->expects($this->once()) + ->method('getChildren') + ->willReturn($children); + $nodeMock->expects($this->any()) + ->method('__call') + ->with('getLevel', []) + ->willReturn(null); + + $nodeMockData = [ + 'data' => [], + 'idField' => 'root', + 'tree' => $treeMock, + ]; + + $this->nodeFactory->expects($this->any()) + ->method('create') + ->with($nodeMockData) + ->willReturn($nodeMock); + + $this->treeFactory->expects($this->once()) + ->method('create') + ->willReturn($treeMock); + + return $nodeMock; + } + + public function testGetMenu() + { + $treeMock = $this->getMockBuilder(\Magento\Framework\Data\Tree::class) + ->disableOriginalConstructor() + ->getMock(); + + $nodeMockData = [ + 'data' => [], + 'idField' => 'root', + 'tree' => $treeMock, + ]; + + $nodeMock = $this->getMockBuilder(\Magento\Framework\Data\Tree\Node::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->nodeFactory->expects($this->any()) + ->method('create') + ->with($nodeMockData) + ->willReturn($nodeMock); - $this->nodeFactory->expects($this->once())->method('create')->willReturn($node); + $this->treeFactory->expects($this->once()) + ->method('create') + ->willReturn($treeMock); - $this->treeFactory->expects($this->once())->method('create')->willReturn($tree); + $topmenuBlock = $this->getTopmenu(); + $this->assertEquals($nodeMock, $topmenuBlock->getMenu()); } } diff --git a/app/code/Magento/Theme/Test/Unit/Console/Command/ThemeUninstallCommandTest.php b/app/code/Magento/Theme/Test/Unit/Console/Command/ThemeUninstallCommandTest.php index 9d4e458b63b9e..433185008fb2c 100644 --- a/app/code/Magento/Theme/Test/Unit/Console/Command/ThemeUninstallCommandTest.php +++ b/app/code/Magento/Theme/Test/Unit/Console/Command/ThemeUninstallCommandTest.php @@ -1,6 +1,6 @@ getMock( \Magento\Backend\Model\Menu::class, [], - [$this->getMock(\Psr\Log\LoggerInterface::class)] + [$this->getMock(\Psr\Log\LoggerInterface::class)], + '', + false ); $menuModel->expects($this->once()) ->method('getParentItems') diff --git a/app/code/Magento/Theme/Test/Unit/Controller/Adminhtml/System/Design/Theme/SaveTest.php b/app/code/Magento/Theme/Test/Unit/Controller/Adminhtml/System/Design/Theme/SaveTest.php index 3f46bec4bd0c5..199cec00d5955 100644 --- a/app/code/Magento/Theme/Test/Unit/Controller/Adminhtml/System/Design/Theme/SaveTest.php +++ b/app/code/Magento/Theme/Test/Unit/Controller/Adminhtml/System/Design/Theme/SaveTest.php @@ -1,7 +1,7 @@ 'message0type', @@ -125,14 +124,14 @@ public function testAfterRenderResult() ) ->willReturn(\Zend_Json::encode($existingMessages)); - $this->dataMock->expects($this->any()) + $this->dataMock->expects($this->once()) ->method('jsonDecode') ->willReturnCallback( function ($data) { return \Zend_Json::decode($data); } ); - $this->dataMock->expects($this->any()) + $this->dataMock->expects($this->exactly(2)) ->method('jsonEncode') ->willReturnCallback( function ($data) { @@ -168,6 +167,56 @@ function ($data) { $this->assertEquals($resultMock, $this->model->afterRenderResult($resultMock, $resultMock)); } + public function testAfterRenderResultWithNoMessages() + { + /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $resultMock */ + $resultMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->cookieManagerMock->expects($this->once()) + ->method('getCookie') + ->with( + MessagePlugin::MESSAGES_COOKIES_NAME, + \Zend_Json::encode([]) + ) + ->willReturn(\Zend_Json::encode([])); + + $this->dataMock->expects($this->once()) + ->method('jsonDecode') + ->willReturnCallback( + function ($data) { + return \Zend_Json::decode($data); + } + ); + $this->dataMock->expects($this->once()) + ->method('jsonEncode') + ->willReturnCallback( + function ($data) { + return \Zend_Json::encode($data); + } + ); + + /** @var Collection|\PHPUnit_Framework_MockObject_MockObject $collectionMock */ + $collectionMock = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $collectionMock->expects($this->once()) + ->method('getItems') + ->willReturn([]); + + $this->managerMock->expects($this->once()) + ->method('getMessages') + ->with(true, null) + ->willReturn($collectionMock); + + $this->cookieMetadataFactoryMock->expects($this->never()) + ->method('createPublicCookieMetadata') + ->willReturn(null); + + $this->assertEquals($resultMock, $this->model->afterRenderResult($resultMock, $resultMock)); + } + public function testAfterRenderResultWithoutExisting() { $messageType = 'message1type'; diff --git a/app/code/Magento/Theme/Test/Unit/CustomerData/MessagesTest.php b/app/code/Magento/Theme/Test/Unit/CustomerData/MessagesTest.php index 8760219d23460..a542e5ea6e4a1 100644 --- a/app/code/Magento/Theme/Test/Unit/CustomerData/MessagesTest.php +++ b/app/code/Magento/Theme/Test/Unit/CustomerData/MessagesTest.php @@ -1,6 +1,6 @@ contextMock->expects($this->once()) ->method('getEventDispatcher') ->willReturn($this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)->getMock()); - + $serializerMock = $this->getMockBuilder(Json::class)->getMock(); $this->model = (new ObjectManager($this))->getObject( \Magento\Theme\Model\Design\Backend\Exceptions::class, [ 'context' => $this->contextMock, 'design' => $this->designMock, + 'serializer' => $serializerMock, ] ); } diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/FileTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/FileTest.php index 7dd8b636210fc..e770aeda00d31 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/FileTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/FileTest.php @@ -1,6 +1,6 @@ getMockObject(\Magento\Framework\Model\Context::class); @@ -46,6 +51,10 @@ public function setUp() $this->urlBuilder = $this->getMockBuilder(\Magento\Framework\UrlInterface::class) ->getMockForAbstractClass(); + $this->mime = $this->getMockBuilder(\Magento\Framework\File\Mime::class) + ->disableOriginalConstructor() + ->getMock(); + $this->fileBackend = new File( $context, $registry, @@ -56,6 +65,13 @@ public function setUp() $filesystem, $this->urlBuilder ); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $objectManager->setBackwardCompatibleProperty( + $this->fileBackend, + 'mime', + $this->mime + ); } public function tearDown() @@ -91,6 +107,10 @@ protected function getMockObjectForAbstractClass($class) public function testAfterLoad() { $value = 'filename.jpg'; + $mime = 'image/jpg'; + + $absoluteFilePath = '/absolute_path/' . $value; + $this->fileBackend->setValue($value); $this->fileBackend->setFieldConfig( [ @@ -109,6 +129,11 @@ public function testAfterLoad() ->method('isExist') ->with('value/' . $value) ->willReturn(true); + $this->mediaDirectory->expects($this->once()) + ->method('getAbsolutePath') + ->with('value/' . $value) + ->willReturn($absoluteFilePath); + $this->urlBuilder->expects($this->once()) ->method('getBaseUrl') ->with(['_type' => UrlInterface::URL_TYPE_MEDIA]) @@ -122,6 +147,11 @@ public function testAfterLoad() ->with('value/' . $value) ->willReturn(['size' => 234234]); + $this->mime->expects($this->once()) + ->method('getMimeType') + ->with($absoluteFilePath) + ->willReturn($mime); + $this->fileBackend->afterLoad(); $this->assertEquals( [ @@ -130,6 +160,8 @@ public function testAfterLoad() 'file' => $value, 'size' => 234234, 'exists' => true, + 'name' => $value, + 'type' => $mime, ] ], $this->fileBackend->getValue() diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/ThemeTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/ThemeTest.php index ab1d55c451b97..8872c4b7c6bf6 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/ThemeTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Backend/ThemeTest.php @@ -1,6 +1,6 @@ objectManager = new ObjectManager($this); $this->dataLoader = $this->getMockBuilder(\Magento\Theme\Model\Design\Config\DataProvider\DataLoader::class) ->disableOriginalConstructor() ->getMock(); @@ -56,6 +84,16 @@ protected function setUp() ->method('create') ->willReturn($this->collection); + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->scopeCodeResolverMock = $this->getMockBuilder(ScopeCodeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->settingCheckerMock = $this->getMockBuilder(SettingChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $this->model = new DataProvider( 'scope', 'scope', @@ -64,6 +102,21 @@ protected function setUp() $this->metadataLoader, $collectionFactory ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'request', + $this->requestMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'scopeCodeResolver', + $this->scopeCodeResolverMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'settingChecker', + $this->settingCheckerMock + ); } public function testGetData() @@ -78,4 +131,119 @@ public function testGetData() $this->assertEquals($data, $this->model->getData()); } + + /** + * @param array $inputMeta + * @param array $expectedMeta + * @param array $request + * @dataProvider getMetaDataProvider + */ + public function testGetMeta(array $inputMeta, array $expectedMeta, array $request) + { + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn($request); + $this->scopeCodeResolverMock->expects($this->any()) + ->method('resolve') + ->with('stores', 1) + ->willReturn('default'); + $this->settingCheckerMock->expects($this->any()) + ->method('isReadOnly') + ->withConsecutive( + ['design/head/welcome', 'stores', 'default'], + ['design/head/logo', 'stores', 'default'], + ['design/head/head', 'stores', 'default'] + ) + ->willReturnOnConsecutiveCalls( + true, + false, + true + ); + + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'meta', + $inputMeta + ); + + $this->assertSame($expectedMeta, $this->model->getMeta()); + } + + /** + * @return array + */ + public function getMetaDataProvider() + { + return [ + [ + [ + 'option1' + ], + [ + 'option1' + ], + [ + 'scope' => 'default' + ] + ], + [ + [ + 'other_settings' => [ + 'children' => [ + 'head' => [ + 'children' => [ + 'head_welcome' => [ + + ], + 'head_logo' => [ + + ], + 'head_head' => [ + + ] + ] + ] + ] + ] + ], + [ + 'other_settings' => [ + 'children' => [ + 'head' => [ + 'children' => [ + 'head_welcome' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'disabled' => true, + 'is_disable_inheritance' => true, + ] + ] + ] + ], + 'head_logo' => [ + + ], + 'head_head' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'disabled' => true, + 'is_disable_inheritance' => true, + ] + ] + ] + ] + ] + ] + ] + ] + ], + [ + 'scope' => 'stores', + 'scope_id' => 1 + ] + ] + ]; + } } diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/FileUploader/FileProcessorTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/FileUploader/FileProcessorTest.php index 1cd1072ce69f1..852453e47c7c3 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/FileUploader/FileProcessorTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/FileUploader/FileProcessorTest.php @@ -1,6 +1,6 @@ uploader->expects($this->once()) ->method('save') ->with('absolute/path/to/tmp/media') - ->willReturn(['file' => 'file.jpg', 'size' => '234234']); + ->willReturn([ + 'file' => 'file.jpg', + 'size' => '234234', + 'type' => 'image/jpg', + 'name' => 'file.jpg', + ]); $this->assertEquals( [ 'file' => 'file.jpg', + 'name' => 'file.jpg', 'size' => '234234', + 'type' => 'image/jpg', 'url' => 'http://magento2.com/pub/media/tmp/' . FileProcessor::FILE_DIR . '/file.jpg' ], $this->fileProcessor->saveToTmp($fieldCode) diff --git a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/PluginTest.php b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/PluginTest.php index d500bea737b91..3f9f78135498c 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Design/Config/PluginTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Design/Config/PluginTest.php @@ -1,6 +1,6 @@ getMockBuilder(\Magento\Framework\Model\Context::class) ->disableOriginalConstructor() ->getMock(); - $this->registry = $this->getMockBuilder( - \Magento\Framework\Registry::class - )->disableOriginalConstructor()->getMock(); $this->localeDate = $this->getMockBuilder( \Magento\Framework\Stdlib\DateTime\TimezoneInterface::class )->getMock(); @@ -65,25 +58,24 @@ protected function setUp() $this->resource = $this->getMockBuilder(\Magento\Theme\Model\ResourceModel\Design::class) ->disableOriginalConstructor() ->getMock(); - $this->resourceCollection = $this->getMockBuilder(\Magento\Theme\Model\ResourceModel\Design\Collection::class) - ->disableOriginalConstructor() - ->getMock(); $this->cacheManager = $this->getMockBuilder(\Magento\Framework\App\CacheInterface::class)->getMock(); $context->expects($this->any()) ->method('getCacheManager') ->willReturn($this->cacheManager); - /** - * @var $context \Magento\Framework\Model\Context - */ - $this->model = new Design( - $context, - $this->registry, - $this->localeDate, - $this->dateTime, - $this->resource, - $this->resourceCollection + $this->serializerMock = $this->getMock(SerializerInterface::class); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $objectManager->getObject( + Design::class, + [ + 'context' => $context, + 'localeDate' => $this->localeDate, + 'dateTime' => $this->dateTime, + 'resource' => $this->resource, + 'serializer' => $this->serializerMock, + ] ); } @@ -119,9 +111,12 @@ public function testLoadChange() ->method('loadChange') ->with($storeId, $date) ->willReturn(false); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->willReturn('serializedData'); $this->cacheManager->expects($this->once()) ->method('save') - ->with(serialize([]), $cacheId, [Design::CACHE_TAG], 86400) + ->with('serializedData', $cacheId, [Design::CACHE_TAG], 86400) ->willReturnSelf(); $this->assertInstanceOf(get_class($this->model), $this->model->loadChange($storeId)); @@ -151,9 +146,16 @@ public function testLoadChangeFromCache() $this->cacheManager->expects($this->once()) ->method('load') ->with($cacheId) - ->willReturn(serialize(['test' => 'data'])); - - $this->assertInstanceOf(get_class($this->model), $this->model->loadChange($storeId)); + ->willReturn('serializedData'); + $data = ['test' => 'data']; + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn($data); + + $change = $this->model->loadChange($storeId); + $this->assertInstanceOf(get_class($this->model), $change); + $this->assertEquals($data, $change->getData()); } /** diff --git a/app/code/Magento/Theme/Test/Unit/Model/Favicon/FaviconTest.php b/app/code/Magento/Theme/Test/Unit/Model/Favicon/FaviconTest.php index ab217b3352231..02a8b7b52e5fd 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Favicon/FaviconTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Favicon/FaviconTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/Test/Unit/Model/Layout/ConfigTest.php b/app/code/Magento/Theme/Test/Unit/Model/Layout/ConfigTest.php index c3f712b47630a..d8d85d0394a80 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Layout/ConfigTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Layout/ConfigTest.php @@ -1,6 +1,6 @@ deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->themeFactoryMock = $this->getMockBuilder(ThemeFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->themeMock = $this->getMockBuilder(Theme::class) + ->disableOriginalConstructor() + ->getMock(); + $this->selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->getMockForAbstractClass(); + $this->dataObjectFactoryMock = $this->getMockBuilder(DataObjectFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->dataObjectMock = $this->getMockBuilder(DataObject::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->themeMock->expects($this->any()) + ->method('getConnection') + ->willReturn($this->connectionMock); + $this->themeFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->themeMock); + $this->connectionMock->expects($this->any()) + ->method('select') + ->willReturn($this->selectMock); + $this->selectMock->expects($this->any()) + ->method('from') + ->willReturnSelf(); + $this->selectMock->expects($this->any()) + ->method('sort') + ->willReturnSelf(); + + $this->model = new InitialThemeSource( + $this->deploymentConfigMock, + $this->themeFactoryMock, + $this->dataObjectFactoryMock + ); + } + + public function testGetNotDeployed() + { + $this->deploymentConfigMock->expects($this->once()) + ->method('isDbAvailable') + ->willReturn(false); + + $this->assertSame([], $this->model->get()); + } + + public function testGet() + { + $this->deploymentConfigMock->expects($this->once()) + ->method('isDbAvailable') + ->willReturn(true); + $this->connectionMock->expects($this->once()) + ->method('fetchAssoc') + ->willReturn( + [ + '1' => [ + 'theme_id' => '1', + 'parent_id' => null, + 'theme_path' => 'Magento/backend', + 'theme_title' => 'Magento 2 backend', + 'is_featured' => '0', + 'area' => 'adminhtml', + 'type' => '0', + 'code' => 'Magento/backend', + ], + '2' => [ + 'theme_id' => '2', + 'parent_id' => null, + 'theme_path' => 'Magento/blank', + 'theme_title' => 'Magento Blank', + 'is_featured' => '0', + 'area' => 'frontend', + 'type' => '0', + 'code' => 'Magento/blank', + ], + '3' => [ + 'theme_id' => '3', + 'parent_id' => '2', + 'theme_path' => 'Magento/luma', + 'theme_title' => 'Magento Luma', + 'is_featured' => '0', + 'area' => 'frontend', + 'type' => '0', + 'code' => 'Magento/luma', + ], + ] + ); + $this->dataObjectFactoryMock->expects($this->once()) + ->method('create') + ->with( + [ + 'Magento/backend' => [ + 'parent_id' => null, + 'theme_path' => 'Magento/backend', + 'theme_title' => 'Magento 2 backend', + 'is_featured' => '0', + 'area' => 'adminhtml', + 'type' => '0', + 'code' => 'Magento/backend', + ], + 'Magento/blank' => [ + 'parent_id' => null, + 'theme_path' => 'Magento/blank', + 'theme_title' => 'Magento Blank', + 'is_featured' => '0', + 'area' => 'frontend', + 'type' => '0', + 'code' => 'Magento/blank', + ], + 'Magento/luma' => [ + 'parent_id' => 'Magento/blank', + 'theme_path' => 'Magento/luma', + 'theme_title' => 'Magento Luma', + 'is_featured' => '0', + 'area' => 'frontend', + 'type' => '0', + 'code' => 'Magento/luma', + ], + ] + ) + ->willReturn($this->dataObjectMock); + $this->dataObjectMock->expects($this->once()) + ->method('getData'); + + $this->model->get(); + } +} diff --git a/app/code/Magento/Theme/Test/Unit/Model/Theme/CollectionTest.php b/app/code/Magento/Theme/Test/Unit/Model/Theme/CollectionTest.php index 57ec5f901d731..41be0a0f265c4 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Theme/CollectionTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Theme/CollectionTest.php @@ -1,6 +1,6 @@ objectManager = new ObjectManagerHelper($this); - } - - public function testGetByFullPath() - { - $path = 'frontend/Magento/luma'; - $collectionFactory = $this->getMock( + $this->collectionFactory = $this->getMock( \Magento\Theme\Model\ResourceModel\Theme\CollectionFactory::class, ['create'], [], '', false ); - $collectionMock = $this->getMock(\Magento\Theme\Model\ResourceModel\Theme\Collection::class, [], [], '', false); - $theme = $this->getMock(\Magento\Framework\View\Design\ThemeInterface::class, [], [], '', false); - $collectionMock->expects( - $this->once() - )->method( - 'getThemeByFullPath' - )->with( - $path - )->will( - $this->returnValue($theme) + $this->themeFactory = $this->getMock( + \Magento\Theme\Model\ThemeFactory::class, + ['create'], + [], + '', + false ); - $collectionFactory->expects($this->once())->method('create')->will($this->returnValue($collectionMock)); - $themeFactory = $this->getMock(\Magento\Theme\Model\ThemeFactory::class, [], [], '', false); - - $themeProvider = $this->objectManager->getObject( + $this->cache = $this->getMockBuilder(\Magento\Framework\App\CacheInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class); + $this->themeProvider = $this->objectManager->getObject( \Magento\Theme\Model\Theme\ThemeProvider::class, [ - 'collectionFactory' => $collectionFactory, - 'themeFactory' => $themeFactory + 'collectionFactory' => $this->collectionFactory, + 'themeFactory' => $this->themeFactory, + 'cache' => $this->cache, + 'serializer' => $this->serializer ] ); - - $this->assertSame($theme, $themeProvider->getThemeByFullPath($path)); + $this->theme = $this->getMock(\Magento\Theme\Model\Theme::class, [], [], '', false); } - public function testGetById() + public function testGetByFullPath() { - $themeId = 755; - $collectionFactory = $this->getMock( - \Magento\Theme\Model\ResourceModel\Theme\CollectionFactory::class, - [], - [], - '', - false - ); - $theme = $this->getMock(\Magento\Theme\Model\Theme::class, [], [], '', false); - $theme->expects($this->once())->method('load')->with($themeId)->will($this->returnSelf()); - $theme->expects($this->once())->method('getId')->will($this->returnValue(1)); - $theme->expects($this->once())->method('__sleep')->will($this->returnValue([])); + $themeArray = ['theme_data' => 'theme_data']; + $this->theme->expects($this->exactly(2)) + ->method('getId') + ->willReturn(self::THEME_ID); + $this->theme->expects($this->exactly(2)) + ->method('toArray') + ->willReturn($themeArray); - $themeFactory = $this->getMock(\Magento\Theme\Model\ThemeFactory::class, ['create'], [], '', false); - $themeFactory->expects($this->once())->method('create')->will($this->returnValue($theme)); + $collectionMock = $this->getMock(\Magento\Theme\Model\ResourceModel\Theme\Collection::class, [], [], '', false); + $collectionMock->expects($this->once()) + ->method('getThemeByFullPath') + ->with(self::THEME_PATH) + ->willReturn($this->theme); + $this->collectionFactory->expects($this->once()) + ->method('create') + ->willReturn($collectionMock); + $this->serializer->expects($this->exactly(2)) + ->method('serialize') + ->with($themeArray) + ->willReturn('serialized theme'); - $cacheMock = $this->getMockBuilder(\Magento\Framework\App\CacheInterface::class) + $deploymentConfig = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) ->disableOriginalConstructor() ->getMock(); - $cacheMock->expects($this->once()) + $deploymentConfig->expects($this->once()) + ->method('isDbAvailable') + ->willReturn(true); + + $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); + $objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap([ + [\Magento\Framework\App\DeploymentConfig::class, $deploymentConfig], + ]); + \Magento\Framework\App\ObjectManager::setInstance($objectManagerMock); + + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeByFullPath(self::THEME_PATH), + 'Unable to load Theme' + ); + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeByFullPath(self::THEME_PATH), + 'Unable to load Theme from object cache' + ); + } + + public function testGetByFullPathWithCache() + { + $deploymentConfig = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $deploymentConfig->expects($this->once()) + ->method('isDbAvailable') + ->willReturn(true); + + $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); + $objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap([ + [\Magento\Framework\App\DeploymentConfig::class, $deploymentConfig], + ]); + \Magento\Framework\App\ObjectManager::setInstance($objectManagerMock); + + $serializedTheme = '{"theme_data":"theme_data"}'; + $themeArray = ['theme_data' => 'theme_data']; + $this->theme->expects($this->once()) + ->method('populateFromArray') + ->with($themeArray) + ->willReturnSelf(); + $this->themeFactory->expects($this->once()) + ->method('create') + ->willReturn($this->theme); + + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($serializedTheme) + ->willReturn($themeArray); + + $this->cache->expects($this->once()) ->method('load') - ->with('theme-by-id-' . $themeId) + ->with('theme' . self::THEME_PATH) + ->willReturn($serializedTheme); + + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeByFullPath(self::THEME_PATH), + 'Unable to load Theme from application cache' + ); + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeByFullPath(self::THEME_PATH), + 'Unable to load Theme from object cache' + ); + } + + public function testGetById() + { + $themeArray = ['theme_data' => 'theme_data']; + $this->theme->expects($this->once()) + ->method('load') + ->with(self::THEME_ID) + ->willReturnSelf(); + $this->theme->expects($this->once()) + ->method('getId') + ->willReturn(self::THEME_ID); + $this->theme->expects($this->once()) + ->method('toArray') + ->willReturn($themeArray); + + $this->themeFactory->expects($this->once())->method('create')->will($this->returnValue($this->theme)); + $this->cache->expects($this->once()) + ->method('load') + ->with('theme-by-id-' . self::THEME_ID) ->willReturn(false); + $this->serializer->expects($this->once()) + ->method('serialize') + ->with($themeArray) + ->willReturn('{"theme_data":"theme_data"}'); - $themeProvider = $this->objectManager->getObject( - \Magento\Theme\Model\Theme\ThemeProvider::class, - [ - 'collectionFactory' => $collectionFactory, - 'themeFactory' => $themeFactory, - 'cache' => $cacheMock - ] + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeById(self::THEME_ID), + 'Unable to load Theme' ); + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeById(self::THEME_ID), + 'Unable to load Theme from object cache' + ); + } - $this->assertSame($theme, $themeProvider->getThemeById($themeId)); + public function testGetByIdWithCache() + { + $serializedTheme = '{"theme_data":"theme_data"}'; + $themeArray = ['theme_data' => 'theme_data']; + $this->theme->expects($this->once()) + ->method('populateFromArray') + ->with($themeArray) + ->willReturnSelf(); + $this->cache->expects($this->once()) + ->method('load') + ->with('theme-by-id-' . self::THEME_ID) + ->willReturn($serializedTheme); + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($serializedTheme) + ->willReturn($themeArray); + $this->themeFactory->expects($this->once()) + ->method('create') + ->willReturn($this->theme); + + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeById(self::THEME_ID), + 'Unable to load Theme from application cache' + ); + $this->assertSame( + $this->theme, + $this->themeProvider->getThemeById(self::THEME_ID), + 'Unable to load Theme from object cache' + ); } public function testGetThemeCustomizations() { - $collectionFactory = $this->getMockBuilder(\Magento\Theme\Model\ResourceModel\Theme\CollectionFactory::class) - ->setMethods(['create']) - ->disableOriginalConstructor() - ->getMock(); - $themeFactory = $this->getMockBuilder(\Magento\Theme\Model\ThemeFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); $collection = $this->getMockBuilder(\Magento\Theme\Model\ResourceModel\Theme\Collection::class) ->disableOriginalConstructor() ->getMock(); - - $collectionFactory->expects($this->once()) - ->method('create') - ->willReturn($collection); $collection->expects($this->once()) ->method('addAreaFilter') ->with(Area::AREA_FRONTEND) @@ -118,15 +254,10 @@ public function testGetThemeCustomizations() ->method('addTypeFilter') ->with(ThemeInterface::TYPE_VIRTUAL) ->willReturnSelf(); + $this->collectionFactory->expects($this->once()) + ->method('create') + ->willReturn($collection); - $themeProvider = $this->objectManager->getObject( - \Magento\Theme\Model\Theme\ThemeProvider::class, - [ - 'collectionFactory' => $collectionFactory, - 'themeFactory' => $themeFactory - ] - ); - - $this->assertInstanceOf(get_class($collection), $themeProvider->getThemeCustomizations()); + $this->assertInstanceOf(get_class($collection), $this->themeProvider->getThemeCustomizations()); } } diff --git a/app/code/Magento/Theme/Test/Unit/Model/Theme/ThemeUninstallerTest.php b/app/code/Magento/Theme/Test/Unit/Model/Theme/ThemeUninstallerTest.php index b625789032173..bd93e2568a809 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Theme/ThemeUninstallerTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Theme/ThemeUninstallerTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Theme\Model\Config\Customization::class, [], [], '', false); @@ -96,6 +101,13 @@ protected function setUp() '', false ); + $this->themeModelFactory = $this->getMock( + \Magento\Theme\Model\ThemeFactory::class, + ['create'], + [], + '', + false + ); $this->validator = $this->getMock(\Magento\Framework\View\Design\Theme\Validator::class, [], [], '', false); $this->appState = $this->getMock(\Magento\Framework\App\State::class, [], [], '', false); @@ -111,6 +123,7 @@ protected function setUp() 'domainFactory' => $this->domainFactory, 'validator' => $this->validator, 'appState' => $this->appState, + 'themeModelFactory' => $this->themeModelFactory ] ); @@ -139,10 +152,8 @@ public function testThemeImageGetter() */ public function testIsVirtual($type, $isVirtual) { - /** @var $themeModel \Magento\Theme\Model\Theme */ - $themeModel = $this->getMock(\Magento\Theme\Model\Theme::class, ['__wakeup'], [], '', false); - $themeModel->setType($type); - $this->assertEquals($isVirtual, $themeModel->isVirtual()); + $this->_model->setType($type); + $this->assertEquals($isVirtual, $this->_model->isVirtual()); } /** @@ -165,10 +176,8 @@ public function isVirtualDataProvider() */ public function testIsPhysical($type, $isPhysical) { - /** @var $themeModel \Magento\Theme\Model\Theme */ - $themeModel = $this->getMock(\Magento\Theme\Model\Theme::class, ['__wakeup'], [], '', false); - $themeModel->setType($type); - $this->assertEquals($isPhysical, $themeModel->isPhysical()); + $this->_model->setType($type); + $this->assertEquals($isPhysical, $this->_model->isPhysical()); } /** @@ -191,10 +200,8 @@ public function isPhysicalDataProvider() */ public function testIsVisible($type, $isVisible) { - /** @var $themeModel \Magento\Theme\Model\Theme */ - $themeModel = $this->getMock(\Magento\Theme\Model\Theme::class, ['__wakeup'], [], '', false); - $themeModel->setType($type); - $this->assertEquals($isVisible, $themeModel->isVisible()); + $this->_model->setType($type); + $this->assertEquals($isVisible, $this->_model->isVisible()); } /** @@ -219,7 +226,7 @@ public function isVisibleDataProvider() */ public function testIsDeletable($themeType, $isDeletable) { - $themeModel = $this->getMock(\Magento\Theme\Model\Theme::class, ['getType', '__wakeup'], [], '', false); + $themeModel = $this->getMock(\Magento\Theme\Model\Theme::class, ['getType'], [], '', false); $themeModel->expects($this->once())->method('getType')->will($this->returnValue($themeType)); /** @var $themeModel \Magento\Theme\Model\Theme */ $this->assertEquals($isDeletable, $themeModel->isDeletable()); @@ -486,4 +493,130 @@ public function getParentTheme() $this->_model->setParentTheme('parent_theme'); $this->assertEquals('parent_theme', $this->_model->getParentTheme()); } + + /** + * @param array $themeData + * @param array $expected + * @dataProvider toArrayDataProvider + */ + public function testToArray(array $themeData, array $expected) + { + $this->_model->setData($themeData); + $this->assertEquals($expected, $this->_model->toArray()); + } + + public function toArrayDataProvider() + { + $parentTheme = $this->getMockBuilder(\Magento\Theme\Model\Theme::class) + ->disableOriginalConstructor() + ->getMock(); + $childTheme = clone $parentTheme; + + $parentTheme->expects($this->once()) + ->method('toArray') + ->willReturn('parent_theme'); + + $childTheme->expects($this->exactly(2)) + ->method('toArray') + ->willReturn('child_theme'); + + return [ + 'null' => [[], []], + 'valid' => [ + ['theme_data' => 'theme_data'], + ['theme_data' => 'theme_data'] + ], + 'valid with parent' => [ + [ + 'theme_data' => 'theme_data', + 'parent_theme' => $parentTheme + ], + [ + 'theme_data' => 'theme_data', + 'parent_theme' => 'parent_theme' + ] + ], + 'valid with children' => [ + [ + 'theme_data' => 'theme_data', + 'inherited_themes' => [ + 'key1' => $childTheme, + 'key2' => $childTheme + ] + ], + [ + 'theme_data' => 'theme_data', + 'inherited_themes' => [ + 'key1' => 'child_theme', + 'key2' => 'child_theme' + ] + ] + ] + ]; + } + + /** + * @param array $value + * @param array $expected + * @param int $expectedCallCount + * + * @dataProvider populateFromArrayDataProvider + */ + public function testPopulateFromArray(array $value, array $expected, $expectedCallCount = 0) + { + $themeMock = $this->getMockBuilder(\Magento\Theme\Model\Theme::class) + ->disableOriginalConstructor() + ->getMock(); + $themeMock->expects($this->exactly($expectedCallCount)) + ->method('populateFromArray') + ->willReturn('theme_instance'); + + $this->themeModelFactory->expects($this->exactly($expectedCallCount)) + ->method('create') + ->willReturn($themeMock); + + $this->_model->populateFromArray($value); + $this->assertEquals($expected, $this->_model->getData()); + } + + public function populateFromArrayDataProvider() + { + return [ + 'valid data' => [ + 'value' => ['theme_data' => 'theme_data'], + 'expected' => ['theme_data' => 'theme_data'] + ], + 'valid data with parent' => [ + 'value' => + [ + 'theme_data' => 'theme_data', + 'parent_theme' => [ + 'theme_data' => 'theme_data' + ] + ], + 'expected' => [ + 'theme_data' => 'theme_data', + 'parent_theme' => 'theme_instance' + ], + 'expected call count' => 1 + ], + 'valid data with children' => [ + 'value' => [ + 'theme_data' => 'theme_data', + 'inherited_themes' => [ + 'key1' => ['theme_data' => 'theme_data'], + 'key2' => ['theme_data' => 'theme_data'] + ] + ], + 'expected' => [ + 'theme_data' => 'theme_data', + 'inherited_themes' => [ + 'key1' => 'theme_instance', + 'key2' => 'theme_instance' + ] + ], + 'expected call count' => 2 + ] + ]; + } } diff --git a/app/code/Magento/Theme/Test/Unit/Model/ThemeValidatorTest.php b/app/code/Magento/Theme/Test/Unit/Model/ThemeValidatorTest.php index d6d3a813e0be4..ade62cf75f830 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/ThemeValidatorTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/ThemeValidatorTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/Test/Unit/Model/_files/frontend/magento_iphone/theme_invalid.xml b/app/code/Magento/Theme/Test/Unit/Model/_files/frontend/magento_iphone/theme_invalid.xml index cfe14f27cfec3..b88b6d7763d56 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/_files/frontend/magento_iphone/theme_invalid.xml +++ b/app/code/Magento/Theme/Test/Unit/Model/_files/frontend/magento_iphone/theme_invalid.xml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/Test/Unit/Observer/ApplyThemeCustomizationObserverTest.php b/app/code/Magento/Theme/Test/Unit/Observer/ApplyThemeCustomizationObserverTest.php index a025c2a85d156..1b17c2715eb13 100644 --- a/app/code/Magento/Theme/Test/Unit/Observer/ApplyThemeCustomizationObserverTest.php +++ b/app/code/Magento/Theme/Test/Unit/Observer/ApplyThemeCustomizationObserverTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/etc/adminhtml/di.xml b/app/code/Magento/Theme/etc/adminhtml/di.xml index 0c043c2e36bac..7d87e73be0b55 100644 --- a/app/code/Magento/Theme/etc/adminhtml/di.xml +++ b/app/code/Magento/Theme/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/adminhtml/menu.xml b/app/code/Magento/Theme/etc/adminhtml/menu.xml index d5b8401853a66..b93648178f48e 100644 --- a/app/code/Magento/Theme/etc/adminhtml/menu.xml +++ b/app/code/Magento/Theme/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/adminhtml/routes.xml b/app/code/Magento/Theme/etc/adminhtml/routes.xml index c94111cc1a420..d53a36e808b66 100644 --- a/app/code/Magento/Theme/etc/adminhtml/routes.xml +++ b/app/code/Magento/Theme/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/config.xml b/app/code/Magento/Theme/etc/config.xml index 5fa88578183d4..9ba3e82a9747e 100644 --- a/app/code/Magento/Theme/etc/config.xml +++ b/app/code/Magento/Theme/etc/config.xml @@ -1,7 +1,7 @@ @@ -48,7 +48,7 @@ Disallow: /*SID= Default welcome msg!
    - Copyright © 2016 Magento. All rights reserved. + Copyright © 2013-2017 Magento, Inc. All rights reserved.
    @@ -64,5 +64,10 @@ Disallow: /*SID= + + + 1 + + diff --git a/app/code/Magento/Theme/etc/di.xml b/app/code/Magento/Theme/etc/di.xml index cee9fc816914b..759508d37bc24 100644 --- a/app/code/Magento/Theme/etc/di.xml +++ b/app/code/Magento/Theme/etc/di.xml @@ -1,7 +1,7 @@ @@ -139,6 +139,33 @@ + + design/theme/theme_id + theme + Magento\Theme\Model\Design\Backend\Theme + true + + + design/theme/ua_regexp + desing_rule + Magento\Theme\Model\Design\Backend\Exceptions + + + design/pagination/pagination_frame + other_settings/pagination + + + design/pagination/pagination_frame_skip + other_settings/pagination + + + design/pagination/anchor_text_for_previous + other_settings/pagination + + + design/pagination/anchor_text_for_next + other_settings/pagination + design/head/shortcut_icon other_settings/head @@ -232,4 +259,14 @@ + + + + + Magento\Theme\Model\Source\InitialThemeSource + themes + + + + diff --git a/app/code/Magento/Theme/etc/events.xml b/app/code/Magento/Theme/etc/events.xml index 94fd427a7a871..574f14709ab25 100644 --- a/app/code/Magento/Theme/etc/events.xml +++ b/app/code/Magento/Theme/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/extension_attributes.xml b/app/code/Magento/Theme/etc/extension_attributes.xml index 54963d97a23cf..302392f78fc08 100644 --- a/app/code/Magento/Theme/etc/extension_attributes.xml +++ b/app/code/Magento/Theme/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/frontend/di.xml b/app/code/Magento/Theme/etc/frontend/di.xml index 85086d694f378..3582aa9de3345 100644 --- a/app/code/Magento/Theme/etc/frontend/di.xml +++ b/app/code/Magento/Theme/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/frontend/events.xml b/app/code/Magento/Theme/etc/frontend/events.xml index 1b744c83879df..97c3ecf930203 100644 --- a/app/code/Magento/Theme/etc/frontend/events.xml +++ b/app/code/Magento/Theme/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/frontend/sections.xml b/app/code/Magento/Theme/etc/frontend/sections.xml index b6f899bfdc4cc..34ced88c82de4 100644 --- a/app/code/Magento/Theme/etc/frontend/sections.xml +++ b/app/code/Magento/Theme/etc/frontend/sections.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/indexer.xml b/app/code/Magento/Theme/etc/indexer.xml index 6b605fbae3758..002cca294181f 100644 --- a/app/code/Magento/Theme/etc/indexer.xml +++ b/app/code/Magento/Theme/etc/indexer.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/etc/module.xml b/app/code/Magento/Theme/etc/module.xml index a30e3e1423e41..42dc82501b408 100644 --- a/app/code/Magento/Theme/etc/module.xml +++ b/app/code/Magento/Theme/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Theme/etc/mview.xml b/app/code/Magento/Theme/etc/mview.xml index 36a94844a9504..24bc771909c89 100644 --- a/app/code/Magento/Theme/etc/mview.xml +++ b/app/code/Magento/Theme/etc/mview.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/i18n/en_US.csv b/app/code/Magento/Theme/i18n/en_US.csv index 3acb4616ea012..d965071ed8089 100644 --- a/app/code/Magento/Theme/i18n/en_US.csv +++ b/app/code/Magento/Theme/i18n/en_US.csv @@ -135,7 +135,7 @@ Configuration,Configuration "This action will delete your custom instructions and reset robots.txt file to system's default settings.","This action will delete your custom instructions and reset robots.txt file to system's default settings." "Default Description","Default Description" "Default welcome msg!","Default welcome msg!" -"Copyright © 2016 Magento. All rights reserved.","Copyright © 2016 Magento. All rights reserved." +"Copyright © 2013-2017 Magento, Inc. All rights reserved.","Copyright © 2013-2017 Magento, Inc. All rights reserved." "Design Config Grid","Design Config Grid" "Rebuild design config grid index","Rebuild design config grid index" "Admin empty","Admin empty" diff --git a/app/code/Magento/Theme/registration.php b/app/code/Magento/Theme/registration.php index 6e72994a28264..58add46ee6909 100644 --- a/app/code/Magento/Theme/registration.php +++ b/app/code/Magento/Theme/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_edit.xml b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_edit.xml index 7886a1f61a639..5db690f54f186 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_edit.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_grid.xml b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_grid.xml index 1c44b080013f0..b3e4744acd8d2 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_grid.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_grid.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_index.xml b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_index.xml index e844eb3344977..3e5166670ab36 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_index.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_contents.xml b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_contents.xml index 9017239e7c2e5..9ec72de7f5361 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_contents.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_contents.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml index a19493b0587d6..b022ad86eab5b 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_wysiwyg_files_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_edit.xml b/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_edit.xml index 18cd928c15f8a..648ccc0c7a482 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_edit.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_index.xml b/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_index.xml index 1a6391ecb6fcd..5a3b004bbfb7f 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_index.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/theme_design_config_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/layouts.xml b/app/code/Magento/Theme/view/adminhtml/layouts.xml index 552ddd7d72ec1..b8292d4b7db50 100644 --- a/app/code/Magento/Theme/view/adminhtml/layouts.xml +++ b/app/code/Magento/Theme/view/adminhtml/layouts.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml index 570f5322e9eb9..da0f6969e46db 100644 --- a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml +++ b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-1column.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml index 0c662a0d467da..b30aaa1fc4052 100644 --- a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml +++ b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-2columns-left.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-empty.xml b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-empty.xml index 2668639c5c26f..1ae61806dea7c 100644 --- a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-empty.xml +++ b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-empty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml index c048ed9829d34..4beee7d41e5db 100644 --- a/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml +++ b/app/code/Magento/Theme/view/adminhtml/page_layout/admin-login.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/requirejs-config.js b/app/code/Magento/Theme/view/adminhtml/requirejs-config.js index bf72402dbf98c..a38a4991aa647 100644 --- a/app/code/Magento/Theme/view/adminhtml/requirejs-config.js +++ b/app/code/Magento/Theme/view/adminhtml/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Theme/view/adminhtml/templates/browser/content.phtml b/app/code/Magento/Theme/view/adminhtml/templates/browser/content.phtml index 9fd6500f1e7f6..492655f3b6fa1 100644 --- a/app/code/Magento/Theme/view/adminhtml/templates/browser/content.phtml +++ b/app/code/Magento/Theme/view/adminhtml/templates/browser/content.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/templates/browser/content/files.phtml b/app/code/Magento/Theme/view/adminhtml/templates/browser/content/files.phtml index 4a7f0d77079d3..bae1e883150b9 100644 --- a/app/code/Magento/Theme/view/adminhtml/templates/browser/content/files.phtml +++ b/app/code/Magento/Theme/view/adminhtml/templates/browser/content/files.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/templates/tabs/fieldset/js.phtml b/app/code/Magento/Theme/view/adminhtml/templates/tabs/fieldset/js.phtml index a4d2088c559c9..8655e5b3a507f 100644 --- a/app/code/Magento/Theme/view/adminhtml/templates/tabs/fieldset/js.phtml +++ b/app/code/Magento/Theme/view/adminhtml/templates/tabs/fieldset/js.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/templates/title.phtml b/app/code/Magento/Theme/view/adminhtml/templates/title.phtml index aea940b2bda5c..3907203fde293 100644 --- a/app/code/Magento/Theme/view/adminhtml/templates/title.phtml +++ b/app/code/Magento/Theme/view/adminhtml/templates/title.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_listing.xml b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_listing.xml index 7f49d37e04cca..87127f75c0d2c 100644 --- a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_listing.xml +++ b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_listing.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/adminhtml/web/css/theme.css b/app/code/Magento/Theme/view/adminhtml/web/css/theme.css index eac172d38b5ba..508fdacf72659 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/css/theme.css +++ b/app/code/Magento/Theme/view/adminhtml/web/css/theme.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Theme/view/adminhtml/web/js/bootstrap.js b/app/code/Magento/Theme/view/adminhtml/web/js/bootstrap.js index d3a48616a9b02..6c5ed9eaf54bf 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/js/bootstrap.js +++ b/app/code/Magento/Theme/view/adminhtml/web/js/bootstrap.js @@ -1,10 +1,10 @@ /** * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ require([ "jquery/fileUploader/jquery.fileupload-ui", "mage/adminhtml/browser", "Magento_Theme/js/form" -]); \ No newline at end of file +]); diff --git a/app/code/Magento/Theme/view/adminhtml/web/js/custom-js-list.js b/app/code/Magento/Theme/view/adminhtml/web/js/custom-js-list.js index 96d9bfeb3d687..cf15cadcc01f6 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/js/custom-js-list.js +++ b/app/code/Magento/Theme/view/adminhtml/web/js/custom-js-list.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Theme/view/adminhtml/web/js/form.js b/app/code/Magento/Theme/view/adminhtml/web/js/form.js index e14a278242c6c..131ea2868aa24 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/js/form.js +++ b/app/code/Magento/Theme/view/adminhtml/web/js/form.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define(["prototype"], function(){ @@ -15,4 +15,4 @@ function parentThemeOnChange(selected, defaultsById) { window.parentThemeOnChange = parentThemeOnChange; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Theme/view/adminhtml/web/js/form/component/robots-reset-button.js b/app/code/Magento/Theme/view/adminhtml/web/js/form/component/robots-reset-button.js index e483632734d45..fdd1e8024cc2b 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/js/form/component/robots-reset-button.js +++ b/app/code/Magento/Theme/view/adminhtml/web/js/form/component/robots-reset-button.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Theme/view/adminhtml/web/js/sortable.js b/app/code/Magento/Theme/view/adminhtml/web/js/sortable.js index 5c08661bb1324..830020e9a5908 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/js/sortable.js +++ b/app/code/Magento/Theme/view/adminhtml/web/js/sortable.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -46,4 +46,4 @@ define([ }); return $.mage.sortable; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Theme/view/adminhtml/web/prototype/magento.css b/app/code/Magento/Theme/view/adminhtml/web/prototype/magento.css index 1f99c991d2228..e989db7091986 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/prototype/magento.css +++ b/app/code/Magento/Theme/view/adminhtml/web/prototype/magento.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Theme/view/adminhtml/web/template/form/button-field.html b/app/code/Magento/Theme/view/adminhtml/web/template/form/button-field.html index fa37c9bdf7e0f..345c9d29c0bb6 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/template/form/button-field.html +++ b/app/code/Magento/Theme/view/adminhtml/web/template/form/button-field.html @@ -1,6 +1,6 @@ @@ -20,4 +20,4 @@
    -
    \ No newline at end of file +
    diff --git a/app/code/Magento/Theme/view/adminhtml/web/template/form/element/button.html b/app/code/Magento/Theme/view/adminhtml/web/template/form/element/button.html index 4f9164baa07d0..743f69805096c 100644 --- a/app/code/Magento/Theme/view/adminhtml/web/template/form/element/button.html +++ b/app/code/Magento/Theme/view/adminhtml/web/template/form/element/button.html @@ -1,6 +1,6 @@ @@ -10,4 +10,4 @@ attr="'data-index': index"> - \ No newline at end of file + diff --git a/app/code/Magento/Theme/view/base/layouts.xml b/app/code/Magento/Theme/view/base/layouts.xml index 05598b5c83e43..c1489a2e66c47 100644 --- a/app/code/Magento/Theme/view/base/layouts.xml +++ b/app/code/Magento/Theme/view/base/layouts.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/base/page_layout/empty.xml b/app/code/Magento/Theme/view/base/page_layout/empty.xml index 82b36252e6f1a..395e629d04ad3 100644 --- a/app/code/Magento/Theme/view/base/page_layout/empty.xml +++ b/app/code/Magento/Theme/view/base/page_layout/empty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/base/requirejs-config.js b/app/code/Magento/Theme/view/base/requirejs-config.js index 3f83f46e430c1..05a0574779543 100644 --- a/app/code/Magento/Theme/view/base/requirejs-config.js +++ b/app/code/Magento/Theme/view/base/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Theme/view/base/templates/root.phtml b/app/code/Magento/Theme/view/base/templates/root.phtml index 5b8e62a03db01..ff5e67235e2fe 100644 --- a/app/code/Magento/Theme/view/base/templates/root.phtml +++ b/app/code/Magento/Theme/view/base/templates/root.phtml @@ -1,6 +1,6 @@ @@ -40,7 +40,7 @@ - + header links diff --git a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml index 25950342da680..fd2d6c6dbb2f1 100644 --- a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml +++ b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/layout/page_calendar.xml b/app/code/Magento/Theme/view/frontend/layout/page_calendar.xml index 353cb19f80da8..4093e646d48b6 100644 --- a/app/code/Magento/Theme/view/frontend/layout/page_calendar.xml +++ b/app/code/Magento/Theme/view/frontend/layout/page_calendar.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/layout/print.xml b/app/code/Magento/Theme/view/frontend/layout/print.xml index 9a4fe9578540d..37d599f301c93 100644 --- a/app/code/Magento/Theme/view/frontend/layout/print.xml +++ b/app/code/Magento/Theme/view/frontend/layout/print.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/layouts.xml b/app/code/Magento/Theme/view/frontend/layouts.xml index 143de45e9d43c..1b1a9c1956c51 100644 --- a/app/code/Magento/Theme/view/frontend/layouts.xml +++ b/app/code/Magento/Theme/view/frontend/layouts.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/page_layout/1column.xml b/app/code/Magento/Theme/view/frontend/page_layout/1column.xml index 268f14012d71a..0ce264465ca61 100644 --- a/app/code/Magento/Theme/view/frontend/page_layout/1column.xml +++ b/app/code/Magento/Theme/view/frontend/page_layout/1column.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/page_layout/2columns-left.xml b/app/code/Magento/Theme/view/frontend/page_layout/2columns-left.xml index 8c7994db8efaf..74fdf1dd176ed 100644 --- a/app/code/Magento/Theme/view/frontend/page_layout/2columns-left.xml +++ b/app/code/Magento/Theme/view/frontend/page_layout/2columns-left.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/page_layout/2columns-right.xml b/app/code/Magento/Theme/view/frontend/page_layout/2columns-right.xml index 3b6569068ac7a..62cda64a18d2c 100644 --- a/app/code/Magento/Theme/view/frontend/page_layout/2columns-right.xml +++ b/app/code/Magento/Theme/view/frontend/page_layout/2columns-right.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/page_layout/3columns.xml b/app/code/Magento/Theme/view/frontend/page_layout/3columns.xml index 3b6569068ac7a..62cda64a18d2c 100644 --- a/app/code/Magento/Theme/view/frontend/page_layout/3columns.xml +++ b/app/code/Magento/Theme/view/frontend/page_layout/3columns.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Theme/view/frontend/requirejs-config.js b/app/code/Magento/Theme/view/frontend/requirejs-config.js index 863a57e419387..4bd09ebd0ad2c 100644 --- a/app/code/Magento/Theme/view/frontend/requirejs-config.js +++ b/app/code/Magento/Theme/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Theme/view/frontend/templates/callouts/left_col.phtml b/app/code/Magento/Theme/view/frontend/templates/callouts/left_col.phtml index 20721c177ca17..5740c91b5b0c5 100644 --- a/app/code/Magento/Theme/view/frontend/templates/callouts/left_col.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/callouts/left_col.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/frontend/templates/html/block.phtml b/app/code/Magento/Theme/view/frontend/templates/html/block.phtml index 89950dd77af5b..a9bffb4bbe269 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/block.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/block.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml b/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml index 72ccd2e648e8d..32933e3a32747 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/collapsible.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/frontend/templates/html/footer.phtml b/app/code/Magento/Theme/view/frontend/templates/html/footer.phtml index 2a22184431ff4..d9de080002604 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/footer.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/footer.phtml @@ -1,6 +1,6 @@ -
    \ No newline at end of file +
    diff --git a/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml b/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml index 2d9c6877800d4..457da22298014 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/frontend/templates/html/sections.phtml b/app/code/Magento/Theme/view/frontend/templates/html/sections.phtml index 04d211407db85..34deb16aa2b9b 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/sections.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/sections.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/frontend/templates/js/components.phtml b/app/code/Magento/Theme/view/frontend/templates/js/components.phtml index e490a6aa04923..bdcb2e9bf7747 100644 --- a/app/code/Magento/Theme/view/frontend/templates/js/components.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/js/components.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Theme/view/frontend/templates/link.phtml b/app/code/Magento/Theme/view/frontend/templates/link.phtml index 42cdddf029931..c75589a8815ed 100644 --- a/app/code/Magento/Theme/view/frontend/templates/link.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/link.phtml @@ -1,6 +1,6 @@
    -
    + +
    -
    + + +
    +
    -
    +
    - \ No newline at end of file + diff --git a/app/code/Magento/Translation/view/base/web/js/i18n-config.js b/app/code/Magento/Translation/view/base/web/js/i18n-config.js index bc828f1dbe989..a880f615c609d 100644 --- a/app/code/Magento/Translation/view/base/web/js/i18n-config.js +++ b/app/code/Magento/Translation/view/base/web/js/i18n-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ 'use strict'; diff --git a/app/code/Magento/Translation/view/frontend/requirejs-config.js b/app/code/Magento/Translation/view/frontend/requirejs-config.js index ad5c6fb3c4973..236bb0e504bdb 100644 --- a/app/code/Magento/Translation/view/frontend/requirejs-config.js +++ b/app/code/Magento/Translation/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Translation/view/frontend/templates/translate_inline.phtml b/app/code/Magento/Translation/view/frontend/templates/translate_inline.phtml index 81e6ad796028e..9d6beb4565cdc 100644 --- a/app/code/Magento/Translation/view/frontend/templates/translate_inline.phtml +++ b/app/code/Magento/Translation/view/frontend/templates/translate_inline.phtml @@ -1,16 +1,16 @@ - - - - + + +
    + data-mage-init='{"translateInline":{"ajaxUrl":"escapeJs($block->escapeUrl($block->getAjaxUrl())) ?>"},"loader":{}}'>
    + +getLayout()->getBlock('adminhtml.user.edit'); ?> + + + diff --git a/app/code/Magento/User/view/adminhtml/web/app-config.js b/app/code/Magento/User/view/adminhtml/web/app-config.js index 7ce567eaf7034..28b2db1ef9dc4 100644 --- a/app/code/Magento/User/view/adminhtml/web/app-config.js +++ b/app/code/Magento/User/view/adminhtml/web/app-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ require.config({ diff --git a/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js b/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js new file mode 100644 index 0000000000000..8d8fc2ee7a07e --- /dev/null +++ b/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js @@ -0,0 +1,28 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery' +], function ($) { + 'use strict'; + + var postData; + + return function (params, elem) { + + elem.on('click', function () { + + postData = { + 'data': { + 'user_id': params.objId, + 'current_password': $('[name="current_password"]').val() + } + }; + + if ($.validator.validateElement($('[name="current_password"]'))) { + window.deleteConfirm(params.message, params.url, postData); + } + }); + }; +}); diff --git a/app/code/Magento/User/view/adminhtml/web/js/roles-tree.js b/app/code/Magento/User/view/adminhtml/web/js/roles-tree.js index 7da85b49b274b..92c67a7bbabab 100644 --- a/app/code/Magento/User/view/adminhtml/web/js/roles-tree.js +++ b/app/code/Magento/User/view/adminhtml/web/js/roles-tree.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ @@ -70,4 +70,4 @@ define([ }); return $.mage.rolesTree; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Usps/Block/Adminhtml/Order/Packaging/Plugin/DisplayGirth.php b/app/code/Magento/Usps/Block/Adminhtml/Order/Packaging/Plugin/DisplayGirth.php index 7fd438d25ede2..79a8cd1a2ff17 100644 --- a/app/code/Magento/Usps/Block/Adminhtml/Order/Packaging/Plugin/DisplayGirth.php +++ b/app/code/Magento/Usps/Block/Adminhtml/Order/Packaging/Plugin/DisplayGirth.php @@ -1,6 +1,6 @@ getService(); } - if ($r->getContainer() == 'FLAT RATE BOX' || $r->getContainer() == 'FLAT RATE ENVELOPE') { + + if ( + strpos($r->getContainer(), 'FLAT RATE ENVELOPE') !== false || + strpos($r->getContainer(), 'FLAT RATE BOX') !== false + ) { $service = 'Priority'; } + $package->addChild('Service', $service); // no matter Letter, Flat or Parcel, use Parcel @@ -794,8 +799,15 @@ public function getCode($type, $code = '') 'first_class_mail_type' => ['LETTER' => __('Letter'), 'FLAT' => __('Flat'), 'PARCEL' => __('Parcel')], 'container' => [ 'VARIABLE' => __('Variable'), - 'FLAT RATE BOX' => __('Flat-Rate Box'), + 'SM FLAT RATE BOX' => __('Small Flat-Rate Box'), + 'MD FLAT RATE BOX' => __('Medium Flat-Rate Box'), + 'LG FLAT RATE BOX' => __('Large Flat-Rate Box'), 'FLAT RATE ENVELOPE' => __('Flat-Rate Envelope'), + 'SM FLAT RATE ENVELOPE' => __('Small Flat-Rate Envelope'), + 'WINDOW FLAT RATE ENVELOPE' => __('Window Flat-Rate Envelope'), + 'GIFT CARD FLAT RATE ENVELOPE' => __('Gift Card Flat-Rate Envelope'), + 'LEGAL FLAT RATE ENVELOPE' => __('Legal Flat-Rate Envelope'), + 'PADDED FLAT RATE ENVELOPE' => __('Padded Flat-Rate Envelope'), 'RECTANGULAR' => __('Rectangular'), 'NONRECTANGULAR' => __('Non-rectangular'), ], @@ -805,73 +817,103 @@ public function getCode($type, $code = '') 'filters' => [ 'within_us' => [ 'method' => [ - 'Priority Mail Express Flat Rate Envelope', - 'Priority Mail Express Flat Rate Envelope Hold For Pickup', - 'Priority Mail Flat Rate Envelope', - 'Priority Mail Large Flat Rate Box', - 'Priority Mail Medium Flat Rate Box', - 'Priority Mail Small Flat Rate Box', - 'Priority Mail Express Hold For Pickup', - 'Priority Mail Express', - 'Priority Mail', - 'Priority Mail Hold For Pickup', - 'Priority Mail Large Flat Rate Box Hold For Pickup', - 'Priority Mail Medium Flat Rate Box Hold For Pickup', - 'Priority Mail Small Flat Rate Box Hold For Pickup', - 'Priority Mail Flat Rate Envelope Hold For Pickup', - 'Priority Mail Small Flat Rate Envelope', - 'Priority Mail Small Flat Rate Envelope Hold For Pickup', - 'First-Class Package Service Hold For Pickup', - 'Retail Ground', - 'Media Mail', - 'First-Class Mail Large Envelope', - 'Priority Mail Express Sunday/Holiday Delivery', - 'Priority Mail Express Sunday/Holiday Delivery Flat Rate Envelope', - 'Priority Mail Express Sunday/Holiday Delivery Flat Rate Boxes', + '13', '27', '16', '22', '17', '28', '2', '3', '1', '33', '34', '35', + '36', '37', '42', '43', '53', '4', '6', '15', '23', '25', '57' ], ], 'from_us' => [ 'method' => [ - 'Priority Mail Express International Flat Rate Envelope', - 'Priority Mail International Flat Rate Envelope', - 'Priority Mail International Large Flat Rate Box', - 'Priority Mail International Medium Flat Rate Box', - 'Priority Mail International Small Flat Rate Box', - 'Priority Mail International Small Flat Rate Envelope', - 'Priority Mail Express International Flat Rate Boxes', - 'Global Express Guaranteed (GXG)', - 'USPS GXG Envelopes', - 'Priority Mail Express International', - 'Priority Mail International', - 'First-Class Mail International Letter', - 'First-Class Mail International Large Envelope', - 'First-Class Package International Service', + 'INT_10', 'INT_8', 'INT_11', 'INT_9', 'INT_16', 'INT_20', 'INT_4', + 'INT_12', 'INT_1', 'INT_2', 'INT_13', 'INT_14', 'INT_15' ], ], ], ], [ - 'containers' => ['FLAT RATE BOX'], + 'containers' => ['SM FLAT RATE BOX'], 'filters' => [ 'within_us' => [ - 'method' => [ - 'Priority Mail Large Flat Rate Box', - 'Priority Mail Medium Flat Rate Box', - 'Priority Mail Small Flat Rate Box', - 'Priority Mail International Large Flat Rate Box', - 'Priority Mail International Medium Flat Rate Box', - 'Priority Mail International Small Flat Rate Box', - 'Priority Mail Express Sunday/Holiday Delivery Flat Rate Boxes', - ], + 'method' => ['28', '57'], ], 'from_us' => [ - 'method' => [ - 'Priority Mail International Large Flat Rate Box', - 'Priority Mail International Medium Flat Rate Box', - 'Priority Mail International Small Flat Rate Box', - 'Priority Mail International DVD Flat Rate priced box', - 'Priority Mail International Large Video Flat Rate priced box', - ], + 'method' => ['INT_16', 'INT_24'], + ], + ] + ], + [ + 'containers' => ['MD FLAT RATE BOX'], + 'filters' => [ + 'within_us' => [ + 'method' => ['17', '57'], + ], + 'from_us' => [ + 'method' => ['INT_9', 'INT_24'], + ], + ] + ], + [ + 'containers' => ['LG FLAT RATE BOX'], + 'filters' => [ + 'within_us' => [ + 'method' => ['22', '57'], + ], + 'from_us' => [ + 'method' => ['INT_11', 'INT_24', 'INT_25'], + ], + ] + ], + [ + 'containers' => ['SM FLAT RATE ENVELOPE'], + 'filters' => [ + 'within_us' => [ + 'method' => ['42', '43'], + ], + 'from_us' => [ + 'method' => ['INT_20'], + ], + ] + ], + [ + 'containers' => ['WINDOW FLAT RATE ENVELOPE'], + 'filters' => [ + 'within_us' => [ + 'method' => ['40', '41'], + ], + 'from_us' => [ + 'method' => ['INT_19'], + ], + ] + ], + [ + 'containers' => ['GIFT CARD FLAT RATE ENVELOPE'], + 'filters' => [ + 'within_us' => [ + 'method' => ['38', '39'], + ], + 'from_us' => [ + 'method' => ['INT_18'], + ], + ] + ], + [ + 'containers' => ['PADDED FLAT RATE ENVELOPE'], + 'filters' => [ + 'within_us' => [ + 'method' => ['62', '63', '64', '46', '29'], + ], + 'from_us' => [ + 'method' => ['INT_27', 'INT_23'], + ], + ] + ], + [ + 'containers' => ['LEGAL FLAT RATE ENVELOPE'], + 'filters' => [ + 'within_us' => [ + 'method' => ['44', '45', '30', '31', '32'], + ], + 'from_us' => [ + 'method' => ['INT_17', 'INT_22'], ], ] ], @@ -879,30 +921,11 @@ public function getCode($type, $code = '') 'containers' => ['FLAT RATE ENVELOPE'], 'filters' => [ 'within_us' => [ - 'method' => [ - 'Priority Mail Flat Rate Envelope', - 'Priority Mail Express Flat Rate Envelope', - 'Priority Mail Express Flat Rate Envelope Hold For Pickup', - 'Priority Mail Flat Rate Envelope', - 'First-Class Mail Large Envelope', - 'Priority Mail Flat Rate Envelope Hold For Pickup', - 'Priority Mail Small Flat Rate Envelope', - 'Priority Mail Small Flat Rate Envelope Hold For Pickup', - 'Priority Mail Express Sunday/Holiday Delivery Flat Rate Envelope', - 'Priority Mail Express Padded Flat Rate Envelope', - ], + 'method' => ['16', '13', '27', '16', '15', '37', '42', '43', '25', '62'], ], 'from_us' => [ 'method' => [ - 'Priority Mail Express International Flat Rate Envelope', - 'Priority Mail International Flat Rate Envelope', - 'First-Class Mail International Large Envelope', - 'Priority Mail International Small Flat Rate Envelope', - 'Priority Mail Express International Legal Flat Rate Envelope', - 'Priority Mail International Gift Card Flat Rate Envelope', - 'Priority Mail International Window Flat Rate Envelope', - 'Priority Mail International Legal Flat Rate Envelope', - 'Priority Mail Express International Padded Flat Rate Envelope', + 'INT_10', 'INT_8', 'INT_14', 'INT_20', 'INT_17', 'INT_18', 'INT_19', 'INT_22', 'INT_27' ], ], ] @@ -911,22 +934,10 @@ public function getCode($type, $code = '') 'containers' => ['RECTANGULAR'], 'filters' => [ 'within_us' => [ - 'method' => [ - 'Priority Mail Express', - 'Priority Mail', - 'Retail Ground', - 'Media Mail', - 'Library Mail', - 'First-Class Package Service', - ], + 'method' => ['3', '1', '4', '6', '7', '61'], ], 'from_us' => [ - 'method' => [ - 'USPS GXG Envelopes', - 'Priority Mail Express International', - 'Priority Mail International', - 'First-Class Package International Service', - ], + 'method' => ['INT_12', 'INT_1', 'INT_2', 'INT_15'], ], ] ], @@ -934,21 +945,10 @@ public function getCode($type, $code = '') 'containers' => ['NONRECTANGULAR'], 'filters' => [ 'within_us' => [ - 'method' => [ - 'Priority Mail Express', - 'Priority Mail', - 'Retail Ground', - 'Media Mail', - 'Library Mail', - ], + 'method' => ['3', '1', '4', '6', '7'], ], 'from_us' => [ - 'method' => [ - 'Global Express Guaranteed (GXG)', - 'Priority Mail Express International', - 'Priority Mail International', - 'First-Class Package International Service', - ], + 'method' => ['INT_4', 'INT_1', 'INT_2', 'INT_15'], ], ] ], @@ -1901,27 +1901,30 @@ protected function _doShipmentRequest(\Magento\Framework\DataObject $request) $response = $client->request()->getBody(); $response = $this->parseXml($response); - if ($response === false || $response->getName() == 'Error') { - $debugData['result'] = [ - 'error' => $response->Description, - 'code' => $response->Number, - 'xml' => $response->asXML(), - ]; - $this->_debug($debugData); - $result->setErrors($debugData['result']['error']); - } else { - if ($recipientUSCountry && $service == 'Priority Express') { - $labelContent = base64_decode((string)$response->EMLabel); - $trackingNumber = (string)$response->EMConfirmationNumber; - } elseif ($recipientUSCountry) { - $labelContent = base64_decode((string)$response->SignatureConfirmationLabel); - $trackingNumber = (string)$response->SignatureConfirmationNumber; + + if($response !== false) { + if ($response->getName() == 'Error') { + $debugData['result'] = [ + 'error' => $response->Description, + 'code' => $response->Number, + 'xml' => $response->asXML(), + ]; + $this->_debug($debugData); + $result->setErrors($debugData['result']['error']); } else { - $labelContent = base64_decode((string)$response->LabelImage); - $trackingNumber = (string)$response->BarcodeNumber; + if ($recipientUSCountry && $service == 'Priority Express') { + $labelContent = base64_decode((string)$response->EMLabel); + $trackingNumber = (string)$response->EMConfirmationNumber; + } elseif ($recipientUSCountry) { + $labelContent = base64_decode((string)$response->SignatureConfirmationLabel); + $trackingNumber = (string)$response->SignatureConfirmationNumber; + } else { + $labelContent = base64_decode((string)$response->LabelImage); + $trackingNumber = (string)$response->BarcodeNumber; + } + $result->setShippingLabelContent($labelContent); + $result->setTrackingNumber($trackingNumber); } - $result->setShippingLabelContent($labelContent); - $result->setTrackingNumber($trackingNumber); } $result->setGatewayResponse($response); diff --git a/app/code/Magento/Usps/Model/Source/Container.php b/app/code/Magento/Usps/Model/Source/Container.php index 45c13f4227dee..8205738fd95ce 100644 --- a/app/code/Magento/Usps/Model/Source/Container.php +++ b/app/code/Magento/Usps/Model/Source/Container.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Usps/Test/Unit/Model/_files/success_usps_response_return_shipment.xml b/app/code/Magento/Usps/Test/Unit/Model/_files/success_usps_response_return_shipment.xml index 449a51aff3a8e..b32520a299123 100644 --- a/app/code/Magento/Usps/Test/Unit/Model/_files/success_usps_response_return_shipment.xml +++ b/app/code/Magento/Usps/Test/Unit/Model/_files/success_usps_response_return_shipment.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Usps/composer.json b/app/code/Magento/Usps/composer.json index 5baccddf48843..15e93d0bea4fb 100644 --- a/app/code/Magento/Usps/composer.json +++ b/app/code/Magento/Usps/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-usps", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/module-store": "100.2.*", "magento/module-shipping": "100.2.*", "magento/module-directory": "100.2.*", diff --git a/app/code/Magento/Usps/etc/adminhtml/di.xml b/app/code/Magento/Usps/etc/adminhtml/di.xml index f60c4d8eb5868..5bc29ffc8cbd9 100644 --- a/app/code/Magento/Usps/etc/adminhtml/di.xml +++ b/app/code/Magento/Usps/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Usps/etc/adminhtml/system.xml b/app/code/Magento/Usps/etc/adminhtml/system.xml index c7b2ce413387f..7e3c3d99521d2 100644 --- a/app/code/Magento/Usps/etc/adminhtml/system.xml +++ b/app/code/Magento/Usps/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Usps/etc/config.xml b/app/code/Magento/Usps/etc/config.xml index 1506971d69487..a5c623d6a8802 100644 --- a/app/code/Magento/Usps/etc/config.xml +++ b/app/code/Magento/Usps/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Usps/etc/di.xml b/app/code/Magento/Usps/etc/di.xml new file mode 100644 index 0000000000000..d0706c7099f87 --- /dev/null +++ b/app/code/Magento/Usps/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + + 1 + 1 + 1 + 1 + + + + diff --git a/app/code/Magento/Usps/etc/module.xml b/app/code/Magento/Usps/etc/module.xml index fb4fca8293f8e..a8ee2cf6cbee9 100644 --- a/app/code/Magento/Usps/etc/module.xml +++ b/app/code/Magento/Usps/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Usps/registration.php b/app/code/Magento/Usps/registration.php index fe382534d3ac8..b1f57ca697f3a 100644 --- a/app/code/Magento/Usps/registration.php +++ b/app/code/Magento/Usps/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Usps/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Usps/view/frontend/layout/checkout_index_index.xml index 5238ecc747c0e..4af078f89a0ef 100644 --- a/app/code/Magento/Usps/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Usps/view/frontend/layout/checkout_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js index b4acad931e3b2..e8c6be9420e32 100644 --- a/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js +++ b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validation-rules.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global define*/ diff --git a/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js index ce5740a70dbe4..ea20e2bd774ac 100644 --- a/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js +++ b/app/code/Magento/Usps/view/frontend/web/js/model/shipping-rates-validator.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*global define*/ diff --git a/app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js b/app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js index ab7d2b340621f..b5fa7f73ec032 100644 --- a/app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js +++ b/app/code/Magento/Usps/view/frontend/web/js/view/shipping-rates-validation.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*browser:true*/ diff --git a/app/code/Magento/Variable/Block/System/Variable.php b/app/code/Magento/Variable/Block/System/Variable.php index f76e6b2d43439..3148037faee45 100644 --- a/app/code/Magento/Variable/Block/System/Variable.php +++ b/app/code/Magento/Variable/Block/System/Variable.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Variable/etc/adminhtml/menu.xml b/app/code/Magento/Variable/etc/adminhtml/menu.xml index fcea4c094de4d..5b2853e1425e4 100644 --- a/app/code/Magento/Variable/etc/adminhtml/menu.xml +++ b/app/code/Magento/Variable/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Variable/etc/adminhtml/routes.xml b/app/code/Magento/Variable/etc/adminhtml/routes.xml index 27a5090c3224a..a1725fcbf0268 100644 --- a/app/code/Magento/Variable/etc/adminhtml/routes.xml +++ b/app/code/Magento/Variable/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Variable/etc/module.xml b/app/code/Magento/Variable/etc/module.xml index 56658740ab4bc..b1411cd7fb026 100644 --- a/app/code/Magento/Variable/etc/module.xml +++ b/app/code/Magento/Variable/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Variable/registration.php b/app/code/Magento/Variable/registration.php index 449b292635629..9b0f8aded417c 100644 --- a/app/code/Magento/Variable/registration.php +++ b/app/code/Magento/Variable/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml b/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml index 90a60c1fac23d..e52681752957d 100644 --- a/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml +++ b/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_index.xml b/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_index.xml index 020c6fa4c83c7..8f470135128a9 100644 --- a/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_index.xml +++ b/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Variable/view/adminhtml/templates/system/variable/js.phtml b/app/code/Magento/Variable/view/adminhtml/templates/system/variable/js.phtml index 67038728dfc3d..d257314f8eb7a 100644 --- a/app/code/Magento/Variable/view/adminhtml/templates/system/variable/js.phtml +++ b/app/code/Magento/Variable/view/adminhtml/templates/system/variable/js.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Variable/view/adminhtml/web/variables.js b/app/code/Magento/Variable/view/adminhtml/web/variables.js index 9a9a688ef4d63..afa83b7246df1 100644 --- a/app/code/Magento/Variable/view/adminhtml/web/variables.js +++ b/app/code/Magento/Variable/view/adminhtml/web/variables.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -131,4 +131,4 @@ window.MagentovariablePlugin = { } }; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Vault/Api/Data/PaymentTokenInterface.php b/app/code/Magento/Vault/Api/Data/PaymentTokenInterface.php index 28848754b40dc..208e44460f59d 100644 --- a/app/code/Magento/Vault/Api/Data/PaymentTokenInterface.php +++ b/app/code/Magento/Vault/Api/Data/PaymentTokenInterface.php @@ -1,6 +1,6 @@ getVaultProvider()->canUseInternal(); + $isInternalAllowed = $this->getConfiguredValue('can_use_internal'); + // if config has't been specified for Vault, need to check payment provider option + if ($isInternalAllowed === null) { + return $this->getVaultProvider()->canUseInternal(); + } + return (bool) $isInternalAllowed; } /** @@ -452,17 +461,14 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) private function attachTokenExtensionAttribute(OrderPaymentInterface $orderPayment) { $additionalInformation = $orderPayment->getAdditionalInformation(); - - $tokenData = isset($additionalInformation[self::TOKEN_METADATA_KEY]) - ? $additionalInformation[self::TOKEN_METADATA_KEY] - : null; - - if ($tokenData === null) { - throw new \LogicException("Token metadata should be defined"); + if (empty($additionalInformation[PaymentTokenInterface::PUBLIC_HASH])) { + throw new \LogicException('Public hash should be defined'); } - $customerId = $tokenData[PaymentTokenInterface::CUSTOMER_ID]; - $publicHash = $tokenData[PaymentTokenInterface::PUBLIC_HASH]; + $customerId = isset($additionalInformation[PaymentTokenInterface::CUSTOMER_ID]) ? + $additionalInformation[PaymentTokenInterface::CUSTOMER_ID] : null; + + $publicHash = $additionalInformation[PaymentTokenInterface::PUBLIC_HASH]; $paymentToken = $this->tokenManagement->getByPublicHash($publicHash, $customerId); @@ -577,7 +583,7 @@ public function assignData(\Magento\Framework\DataObject $data) public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null) { return $this->getVaultProvider()->isAvailable($quote) - && $this->config->getValue(self::$activeKey, $this->getStore() ?: $quote->getStoreId()); + && $this->config->getValue(self::$activeKey, $this->getStore() ?: ($quote ? $quote->getStoreId() : null)); } /** diff --git a/app/code/Magento/Vault/Model/PaymentMethodList.php b/app/code/Magento/Vault/Model/PaymentMethodList.php new file mode 100644 index 0000000000000..fd3de3139522e --- /dev/null +++ b/app/code/Magento/Vault/Model/PaymentMethodList.php @@ -0,0 +1,78 @@ +instanceFactory = $instanceFactory; + $this->paymentMethodList = $paymentMethodList; + } + + /** + * @inheritdoc + */ + public function getList($storeId) + { + return $this->filterList($this->paymentMethodList->getList($storeId)); + } + + /** + * @inheritdoc + */ + public function getActiveList($storeId) + { + return $this->filterList($this->paymentMethodList->getActiveList($storeId)); + } + + /** + * Filter vault methods from payments + * @param PaymentMethodInterface[] $list + * @return VaultPaymentInterface[] + */ + private function filterList(array $list) + { + $paymentMethods = array_map( + function (PaymentMethodInterface $paymentMethod) { + return $this->instanceFactory->create($paymentMethod); + }, + $list + ); + + $availableMethods = array_filter( + $paymentMethods, + function (MethodInterface $methodInstance) { + return $methodInstance instanceof VaultPaymentInterface; + } + ); + return array_values($availableMethods); + } +} diff --git a/app/code/Magento/Vault/Model/PaymentToken.php b/app/code/Magento/Vault/Model/PaymentToken.php index 65b9f5528940f..7a03147ed19c7 100644 --- a/app/code/Magento/Vault/Model/PaymentToken.php +++ b/app/code/Magento/Vault/Model/PaymentToken.php @@ -1,6 +1,6 @@ setIsActive(false); + $tokenModel->setIsVisible(false); $tokenModel->save(); return true; diff --git a/app/code/Magento/Vault/Model/ResourceModel/PaymentToken.php b/app/code/Magento/Vault/Model/ResourceModel/PaymentToken.php index b9ffc69cf7fe8..d688d39846a28 100644 --- a/app/code/Magento/Vault/Model/ResourceModel/PaymentToken.php +++ b/app/code/Magento/Vault/Model/ResourceModel/PaymentToken.php @@ -1,6 +1,6 @@ getPaymentTokenManagement() - ->getByPaymentId($this->getOrderPaymentEntityId()) - ->getEntityId(); + $paymentToken = $this->getPaymentTokenManagement()->getByPaymentId($this->getOrderPaymentEntityId()); + if ($paymentToken === null) { + throw new NoSuchEntityException(__('No available payment tokens for specified order payment.')); + } + return $paymentToken->getEntityId(); } /** diff --git a/app/code/Magento/Vault/Model/Ui/TokenUiComponent.php b/app/code/Magento/Vault/Model/Ui/TokenUiComponent.php index 69a5587323126..951d770890a03 100644 --- a/app/code/Magento/Vault/Model/Ui/TokenUiComponent.php +++ b/app/code/Magento/Vault/Model/Ui/TokenUiComponent.php @@ -1,6 +1,6 @@ getComponentForToken($token); - $vaultPayments[$paymentCode . '_item_' . $i] = [ - 'config' => $component->getConfig(), + $config = $component->getConfig(); + $vaultPaymentCode = !empty($config['code']) ? $config['code'] : $paymentCode; + $vaultPayments[$vaultPaymentCode . '_' . $i] = [ + 'config' => $config, 'component' => $component->getName() ]; } @@ -98,21 +99,17 @@ public function getConfig() } /** - * Get list of available vault ui token providers + * Get list of available vault ui token providers. + * * @return TokenUiComponentProviderInterface[] */ private function getComponentProviders() { $providers = []; $storeId = $this->storeManager->getStore()->getId(); - $paymentMethods = $this->getPaymentDataHelper()->getStoreMethods($storeId); + $vaultPaymentMethods = $this->getVaultPaymentList()->getActiveList($storeId); - foreach ($paymentMethods as $method) { - /** VaultPaymentInterface $method */ - if (!$method instanceof VaultPaymentInterface || !$method->isActive($storeId)) { - continue; - } - + foreach ($vaultPaymentMethods as $method) { $providerCode = $method->getProviderCode(); $componentProvider = $this->getComponentProvider($providerCode); if ($componentProvider === null) { @@ -139,15 +136,15 @@ private function getComponentProvider($vaultProviderCode) } /** - * Get payment data helper instance - * @return Data + * Get instance of vault payment list instance + * @return PaymentMethodListInterface * @deprecated */ - private function getPaymentDataHelper() + private function getVaultPaymentList() { - if ($this->paymentDataHelper === null) { - $this->paymentDataHelper = ObjectManager::getInstance()->get(Data::class); + if ($this->vaultPaymentList === null) { + $this->vaultPaymentList = ObjectManager::getInstance()->get(PaymentMethodListInterface::class); } - return $this->paymentDataHelper; + return $this->vaultPaymentList; } } diff --git a/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php b/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php index 8bf88e7a94f50..26596fe8eb181 100644 --- a/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php +++ b/app/code/Magento/Vault/Model/Ui/VaultConfigProvider.php @@ -1,6 +1,6 @@ getVaultPaymentMethodList(); - $customerId = $this->session->getCustomerId(); $storeId = $this->storeManager->getStore()->getId(); + $vaultPayments = $this->getVaultPaymentList()->getActiveList($storeId); + $customerId = $this->session->getCustomerId(); foreach ($vaultPayments as $method) { $availableMethods[$method->getCode()] = [ @@ -73,36 +72,15 @@ public function getConfig() } /** - * Get list of active Vault payment methods - * @return array - */ - private function getVaultPaymentMethodList() - { - $availableMethods = []; - $storeId = $this->storeManager->getStore()->getId(); - - $paymentMethods = $this->getPaymentDataHelper()->getStoreMethods($storeId); - foreach ($paymentMethods as $method) { - /** VaultPaymentInterface $method */ - if (!$method instanceof VaultPaymentInterface) { - continue; - } - $availableMethods[] = $method; - } - - return $availableMethods; - } - - /** - * Get payment data helper instance - * @return Data + * Get vault payment list instance + * @return PaymentMethodListInterface * @deprecated */ - private function getPaymentDataHelper() + private function getVaultPaymentList() { - if ($this->paymentDataHelper === null) { - $this->paymentDataHelper = ObjectManager::getInstance()->get(Data::class); + if ($this->vaultPaymentList === null) { + $this->vaultPaymentList = ObjectManager::getInstance()->get(PaymentMethodListInterface::class); } - return $this->paymentDataHelper; + return $this->vaultPaymentList; } } diff --git a/app/code/Magento/Vault/Model/VaultPaymentInterface.php b/app/code/Magento/Vault/Model/VaultPaymentInterface.php index 7b932ba85835d..da45ee29ea97e 100644 --- a/app/code/Magento/Vault/Model/VaultPaymentInterface.php +++ b/app/code/Magento/Vault/Model/VaultPaymentInterface.php @@ -1,6 +1,6 @@ setAdditionalInformation( - Vault::TOKEN_METADATA_KEY, [ PaymentTokenInterface::CUSTOMER_ID => $customerId, PaymentTokenInterface::PUBLIC_HASH => $tokenPublicHash diff --git a/app/code/Magento/Vault/Observer/VaultEnableAssigner.php b/app/code/Magento/Vault/Observer/VaultEnableAssigner.php index db112cf453912..cd64a43f1c0ce 100644 --- a/app/code/Magento/Vault/Observer/VaultEnableAssigner.php +++ b/app/code/Magento/Vault/Observer/VaultEnableAssigner.php @@ -1,6 +1,6 @@ vaultPaymentList = $vaultPaymentList; + $this->paymentMethodList = $paymentMethodList; + $this->storeManager = $storeManager; + } + + /** + * Checkout LayoutProcessor before process plugin. + * + * @param \Magento\Checkout\Block\Checkout\LayoutProcessor $processor + * @param array $jsLayout + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeProcess(\Magento\Checkout\Block\Checkout\LayoutProcessor $processor, $jsLayout) + { + $configuration = &$jsLayout['components']['checkout']['children']['steps']['children']['billing-step'] + ['children']['payment']['children']['renders']['children']; + + if (!isset($configuration)) { + return [$jsLayout]; + } + + $storeId = $this->storeManager->getStore()->getId(); + $activePaymentMethodList = $this->paymentMethodList->getActiveList($storeId); + $activeVaultList = $this->vaultPaymentList->getActiveList($storeId); + $getCodeFunc = function ($method) { + return $method->getCode(); + }; + $getProviderCodeFunc = function ($method) { + return $method->getProviderCode(); + }; + $activePaymentMethodCodes = array_map($getCodeFunc, $activePaymentMethodList); + $activeVaultProviderCodes = array_map($getProviderCodeFunc, $activeVaultList); + $activePaymentMethodCodes = array_merge( + $activePaymentMethodCodes, + $activeVaultProviderCodes + ); + + foreach ($configuration as $paymentGroup => $groupConfig) { + $notActivePaymentMethodCodes = array_diff(array_keys($groupConfig['methods']), $activePaymentMethodCodes); + foreach ($notActivePaymentMethodCodes as $notActivePaymentMethodCode) { + unset($configuration[$paymentGroup]['methods'][$notActivePaymentMethodCode]); + } + if ($paymentGroup === 'vault' && !empty($activeVaultProviderCodes)) { + continue; + } + if (empty($configuration[$paymentGroup]['methods'])) { + unset($configuration[$paymentGroup]); + } + } + + return [$jsLayout]; + } +} diff --git a/app/code/Magento/Vault/Setup/InstallSchema.php b/app/code/Magento/Vault/Setup/InstallSchema.php index 6f505d130e455..ebf8a576b0a34 100644 --- a/app/code/Magento/Vault/Setup/InstallSchema.php +++ b/app/code/Magento/Vault/Setup/InstallSchema.php @@ -1,6 +1,6 @@ startSetup(); + // data update for Vault module < 2.0.1 if (version_compare($context->getVersion(), '2.0.1', '<')) { - $connection = $setup->getConnection(); - $connection->update($setup->getTable(InstallSchema::PAYMENT_TOKEN_TABLE), [ + // update sets credit card as default token type + $setup->getConnection()->update($setup->getTable(InstallSchema::PAYMENT_TOKEN_TABLE), [ PaymentTokenInterface::TYPE => CreditCardTokenFactory::TOKEN_TYPE_CREDIT_CARD ], PaymentTokenInterface::TYPE . ' = ""'); } + + // data update for Vault module < 2.0.2 + if (version_compare($context->getVersion(), '2.0.2', '<')) { + // update converts additional info with token metadata to single dimensional array + $salesConnection = $setup->getConnection(self::$salesConnectionName); + $select = $salesConnection->select() + ->from($setup->getTable('sales_order_payment'), 'entity_id') + ->columns(['additional_information']) + ->where('additional_information LIKE ?', '%token_metadata%'); + + $items = $salesConnection->fetchAll($select); + foreach ($items as $item) { + $additionalInfo = unserialize($item['additional_information']); + $additionalInfo[PaymentTokenInterface::CUSTOMER_ID] = + $additionalInfo['token_metadata'][PaymentTokenInterface::CUSTOMER_ID]; + $additionalInfo[PaymentTokenInterface::PUBLIC_HASH] = + $additionalInfo['token_metadata'][PaymentTokenInterface::PUBLIC_HASH]; + unset($additionalInfo['token_metadata']); + + $salesConnection->update( + $setup->getTable('sales_order_payment'), + ['additional_information' => serialize($additionalInfo)], + ['entity_id = ?' => $item['entity_id']] + ); + } + } + $setup->endSetup(); } } diff --git a/app/code/Magento/Vault/Test/Unit/Block/Customer/AccountTokensTest.php b/app/code/Magento/Vault/Test/Unit/Block/Customer/AccountTokensTest.php index d2de86c58c0b7..8f7c7573e0660 100644 --- a/app/code/Magento/Vault/Test/Unit/Block/Customer/AccountTokensTest.php +++ b/app/code/Magento/Vault/Test/Unit/Block/Customer/AccountTokensTest.php @@ -1,6 +1,6 @@ objectManager = new ObjectManager($this); + $this->vaultProvider = $this->getMock(MethodInterface::class); } /** @@ -50,10 +59,12 @@ public function testAuthorizeNotOrderPayment() } /** + * @param array $additionalInfo * @expectedException \LogicException - * @expectedExceptionMessage Token metadata should be defined + * @expectedExceptionMessage Public hash should be defined + * @dataProvider additionalInfoDataProvider */ - public function testAuthorizeNoTokenMetadata() + public function testAuthorizeNoTokenMetadata(array $additionalInfo) { $paymentModel = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() @@ -61,13 +72,26 @@ public function testAuthorizeNoTokenMetadata() $paymentModel->expects(static::once()) ->method('getAdditionalInformation') - ->willReturn([]); + ->willReturn($additionalInfo); /** @var Vault $model */ $model = $this->objectManager->getObject(Vault::class); $model->authorize($paymentModel, 0); } + /** + * Get list of additional information variations + * @return array + */ + public function additionalInfoDataProvider() + { + return [ + ['additionalInfo' => []], + ['additionalInfo' => ['customer_id' => 1]], + ['additionalInfo' => ['public_hash' => null]], + ]; + } + /** * @expectedException \LogicException * @expectedExceptionMessage No token found @@ -86,10 +110,8 @@ public function testAuthorizeNoToken() ->method('getAdditionalInformation') ->willReturn( [ - Vault::TOKEN_METADATA_KEY => [ - PaymentTokenInterface::CUSTOMER_ID => $customerId, - PaymentTokenInterface::PUBLIC_HASH => $publicHash - ] + PaymentTokenInterface::CUSTOMER_ID => $customerId, + PaymentTokenInterface::PUBLIC_HASH => $publicHash ] ); $tokenManagement->expects(static::once()) @@ -124,8 +146,6 @@ public function testAuthorize() $commandManagerPool = $this->getMock(CommandManagerPoolInterface::class); $commandManager = $this->getMock(CommandManagerInterface::class); - $vaultProvider = $this->getMock(MethodInterface::class); - $tokenManagement = $this->getMock(PaymentTokenManagementInterface::class); $token = $this->getMock(PaymentTokenInterface::class); @@ -133,10 +153,8 @@ public function testAuthorize() ->method('getAdditionalInformation') ->willReturn( [ - Vault::TOKEN_METADATA_KEY => [ - PaymentTokenInterface::CUSTOMER_ID => $customerId, - PaymentTokenInterface::PUBLIC_HASH => $publicHash - ] + PaymentTokenInterface::CUSTOMER_ID => $customerId, + PaymentTokenInterface::PUBLIC_HASH => $publicHash ] ); $tokenManagement->expects(static::once()) @@ -150,7 +168,7 @@ public function testAuthorize() ->method('setVaultPaymentToken') ->with($token); - $vaultProvider->expects(static::atLeastOnce()) + $this->vaultProvider->expects(static::atLeastOnce()) ->method('getCode') ->willReturn($vaultProviderCode); $commandManagerPool->expects(static::once()) @@ -177,7 +195,7 @@ public function testAuthorize() [ 'tokenManagement' => $tokenManagement, 'commandManagerPool' => $commandManagerPool, - 'vaultProvider' => $vaultProvider + 'vaultProvider' => $this->vaultProvider ] ); $model->authorize($paymentModel, $amount); @@ -224,10 +242,9 @@ public function testIsAvailable($isAvailableProvider, $isActive, $expected) { $storeId = 1; $quote = $this->getMockForAbstractClass(CartInterface::class); - $vaultProvider = $this->getMockForAbstractClass(MethodInterface::class); $config = $this->getMockForAbstractClass(ConfigInterface::class); - $vaultProvider->expects(static::once()) + $this->vaultProvider->expects(static::once()) ->method('isAvailable') ->with($quote) ->willReturn($isAvailableProvider); @@ -244,7 +261,7 @@ public function testIsAvailable($isAvailableProvider, $isActive, $expected) /** @var Vault $model */ $model = $this->objectManager->getObject(Vault::class, [ 'config' => $config, - 'vaultProvider' => $vaultProvider + 'vaultProvider' => $this->vaultProvider ]); $actual = $model->isAvailable($quote); static::assertEquals($expected, $actual); @@ -263,4 +280,82 @@ public function isAvailableDataProvider() ['isAvailableProvider' => true, 'isActiveVault' => true, 'expected' => true], ]; } + + /** + * @covers \Magento\Vault\Model\Method\Vault::isAvailable + */ + public function testIsAvailableWithoutQuote() + { + $quote = null; + $config = $this->getMockForAbstractClass(ConfigInterface::class); + + $this->vaultProvider->expects(static::once()) + ->method('isAvailable') + ->with($quote) + ->willReturn(true); + + $config->expects(static::once()) + ->method('getValue') + ->with('active', $quote) + ->willReturn(false); + + /** @var Vault $model */ + $model = $this->objectManager->getObject(Vault::class, [ + 'config' => $config, + 'vaultProvider' => $this->vaultProvider + ]); + static::assertFalse($model->isAvailable($quote)); + } + + /** + * @covers \Magento\Vault\Model\Method\Vault::canUseInternal + * @param bool|null $configValue + * @param bool|null $paymentValue + * @param bool $expected + * @dataProvider internalUsageDataProvider + */ + public function testCanUseInternal($configValue, $paymentValue, $expected) + { + $handlerPool = $this->getMock(ValueHandlerPoolInterface::class); + $handler = $this->getMock(ValueHandlerInterface::class); + + $handlerPool->expects(static::once()) + ->method('get') + ->with('can_use_internal') + ->willReturn($handler); + + $handler->expects(static::once()) + ->method('handle') + ->with(['field' => 'can_use_internal'], null) + ->willReturn($configValue); + + $this->vaultProvider->expects(static::any()) + ->method('canUseInternal') + ->willReturn($paymentValue); + + /** @var Vault $model */ + $model = $this->objectManager->getObject(Vault::class, [ + 'vaultProvider' => $this->vaultProvider, + 'valueHandlerPool' => $handlerPool, + ]); + static::assertEquals($expected, $model->canUseInternal()); + } + + /** + * Get list of variations for testing canUseInternal method + * @return array + */ + public function internalUsageDataProvider() + { + return [ + ['configValue' => true, 'paymentValue' => true, 'expected' => true], + ['configValue' => true, 'paymentValue' => null, 'expected' => true], + ['configValue' => true, 'paymentValue' => false, 'expected' => true], + ['configValue' => false, 'paymentValue' => true, 'expected' => false], + ['configValue' => false, 'paymentValue' => false, 'expected' => false], + ['configValue' => null, 'paymentValue' => true, 'expected' => true], + ['configValue' => null, 'paymentValue' => false, 'expected' => false], + ['configValue' => null, 'paymentValue' => null, 'expected' => false], + ]; + } } diff --git a/app/code/Magento/Vault/Test/Unit/Model/PaymentMethodListTest.php b/app/code/Magento/Vault/Test/Unit/Model/PaymentMethodListTest.php new file mode 100644 index 0000000000000..73a625fdf9a05 --- /dev/null +++ b/app/code/Magento/Vault/Test/Unit/Model/PaymentMethodListTest.php @@ -0,0 +1,74 @@ +paymentMethodList = $this->getMock(PaymentMethodListInterface::class); + $this->instanceFactory = $this->getMockBuilder(InstanceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->vaultPaymentList = new PaymentMethodList($this->paymentMethodList, $this->instanceFactory); + } + + /** + * @covers \Magento\Vault\Model\PaymentMethodList::getActiveList + */ + public function testGetActivePaymentList() + { + $storeId = 1; + $vaultPayment = $this->getMock(VaultPaymentInterface::class); + $paymentMethodInterface1 = $this->getMock(PaymentMethodInterface::class); + $paymentMethodInterface2 = $this->getMock(PaymentMethodInterface::class); + $activePayments = [ + $paymentMethodInterface1, + $paymentMethodInterface2 + ]; + + $this->paymentMethodList->expects(static::once()) + ->method('getActiveList') + ->with($storeId) + ->willReturn($activePayments); + + $this->instanceFactory->expects(static::exactly(2)) + ->method('create') + ->willReturnMap([ + [$paymentMethodInterface1, $this->getMock(MethodInterface::class)], + [$paymentMethodInterface2, $vaultPayment] + ]); + + $vaultPayments = $this->vaultPaymentList->getActiveList($storeId); + static::assertCount(1, $vaultPayments); + static::assertInstanceOf(VaultPaymentInterface::class, $vaultPayment); + } +} diff --git a/app/code/Magento/Vault/Test/Unit/Model/PaymentTokenManagementTest.php b/app/code/Magento/Vault/Test/Unit/Model/PaymentTokenManagementTest.php index 8784522a80f7a..2f662c1a8384a 100644 --- a/app/code/Magento/Vault/Test/Unit/Model/PaymentTokenManagementTest.php +++ b/app/code/Magento/Vault/Test/Unit/Model/PaymentTokenManagementTest.php @@ -1,6 +1,6 @@ paymentTokenRepository = $this->getMockBuilder(PaymentTokenRepositoryInterface::class) @@ -138,6 +148,38 @@ protected function setUp() $this->vaultPayment = $this->getMockForAbstractClass(VaultPaymentInterface::class); $this->objectManager = new ObjectManager($this); + + $this->initStoreMock(); + + $this->tokenComponentProvider = $this->getMock(TokenUiComponentProviderInterface::class); + + $this->configProvider = new TokensConfigProvider( + $this->session, + $this->paymentTokenRepository, + $this->filterBuilder, + $this->searchCriteriaBuilder, + $this->storeManager, + $this->dateTimeFactory, + [ + self::VAULT_PROVIDER_CODE => $this->tokenComponentProvider + ] + ); + + $this->objectManager->setBackwardCompatibleProperty( + $this->configProvider, + 'paymentDataHelper', + $this->paymentDataHelper + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->configProvider, + 'paymentTokenManagement', + $this->paymentTokenManagement + ); + $this->objectManager->setBackwardCompatibleProperty( + $this->configProvider, + 'orderRepository', + $this->orderRepository + ); } /** @@ -147,8 +189,6 @@ public function testGetTokensComponentsRegisteredCustomer() { $customerId = 1; - $this->initStoreMock(); - $this->session->expects(static::once()) ->method('getCustomerId') ->willReturn($customerId); @@ -170,7 +210,7 @@ public function testGetTokensComponentsRegisteredCustomer() $token = $this->getMockBuilder(PaymentTokenInterface::class) ->getMockForAbstractClass(); - list($tokenUiComponent, $tokenUiComponentProvider) = $this->getTokenUiComponentProvider($token); + $tokenUiComponent = $this->getTokenUiComponentProvider($token); $searchCriteria = $this->getSearchCriteria($customerId, self::ENTITY_ID, self::VAULT_PROVIDER_CODE); @@ -197,25 +237,7 @@ public function testGetTokensComponentsRegisteredCustomer() ->method('getItems') ->willReturn([$token]); - $configProvider = new TokensConfigProvider( - $this->session, - $this->paymentTokenRepository, - $this->filterBuilder, - $this->searchCriteriaBuilder, - $this->storeManager, - $this->dateTimeFactory, - [ - self::VAULT_PROVIDER_CODE => $tokenUiComponentProvider - ] - ); - - $this->objectManager->setBackwardCompatibleProperty( - $configProvider, - 'paymentDataHelper', - $this->paymentDataHelper - ); - - static::assertEquals([$tokenUiComponent], $configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); + static::assertEquals([$tokenUiComponent], $this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); } /** @@ -263,7 +285,7 @@ public function testGetTokensComponentsGuestCustomer() ->method('getEntityId') ->willReturn(self::ENTITY_ID); - list($tokenUiComponent, $tokenUiComponentProvider) = $this->getTokenUiComponentProvider($token); + $tokenUiComponent = $this->getTokenUiComponentProvider($token); $searchCriteria = $this->getSearchCriteria($customerId, self::ENTITY_ID, self::VAULT_PROVIDER_CODE); @@ -290,35 +312,7 @@ public function testGetTokensComponentsGuestCustomer() ->method('getItems') ->willReturn([$token]); - $configProvider = new TokensConfigProvider( - $this->session, - $this->paymentTokenRepository, - $this->filterBuilder, - $this->searchCriteriaBuilder, - $this->storeManager, - $this->dateTimeFactory, - [ - self::VAULT_PROVIDER_CODE => $tokenUiComponentProvider - ] - ); - - $this->objectManager->setBackwardCompatibleProperty( - $configProvider, - 'paymentDataHelper', - $this->paymentDataHelper - ); - $this->objectManager->setBackwardCompatibleProperty( - $configProvider, - 'paymentTokenManagement', - $this->paymentTokenManagement - ); - $this->objectManager->setBackwardCompatibleProperty( - $configProvider, - 'orderRepository', - $this->orderRepository - ); - - static::assertEquals([$tokenUiComponent], $configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); + static::assertEquals([$tokenUiComponent], $this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); } /** @@ -330,8 +324,6 @@ public function testGetTokensComponentsGuestCustomerOrderNotFound($exception) { $customerId = null; - $this->initStoreMock(); - $this->session->expects(static::once()) ->method('getCustomerId') ->willReturn($customerId); @@ -366,35 +358,7 @@ public function testGetTokensComponentsGuestCustomerOrderNotFound($exception) $this->searchCriteriaBuilder->expects(self::never()) ->method('addFilters'); - $configProvider = new TokensConfigProvider( - $this->session, - $this->paymentTokenRepository, - $this->filterBuilder, - $this->searchCriteriaBuilder, - $this->storeManager, - $this->dateTimeFactory, - [ - self::VAULT_PROVIDER_CODE => $this->getMock(TokenUiComponentProviderInterface::class) - ] - ); - - $this->objectManager->setBackwardCompatibleProperty( - $configProvider, - 'paymentDataHelper', - $this->paymentDataHelper - ); - $this->objectManager->setBackwardCompatibleProperty( - $configProvider, - 'paymentTokenManagement', - $this->paymentTokenManagement - ); - $this->objectManager->setBackwardCompatibleProperty( - $configProvider, - 'orderRepository', - $this->orderRepository - ); - - static::assertEmpty($configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); + static::assertEmpty($this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); } /** @@ -453,18 +417,66 @@ public function testGetTokensComponentsEmptyComponentProvider() static::assertEmpty($configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); } + /** + * @covers \Magento\Vault\Model\Ui\Adminhtml\TokensConfigProvider::getTokensComponents + */ + public function testGetTokensComponentsForGuestCustomerWithoutStoredTokens() + { + $this->session->expects(static::once()) + ->method('getCustomerId') + ->willReturn(null); + + $this->paymentDataHelper->expects(static::once()) + ->method('getMethodInstance') + ->with(self::VAULT_PAYMENT_CODE) + ->willReturn($this->vaultPayment); + + $this->vaultPayment->expects(static::once()) + ->method('isActive') + ->with(self::STORE_ID) + ->willReturn(true); + $this->vaultPayment->expects(static::once()) + ->method('getProviderCode') + ->willReturn(self::VAULT_PROVIDER_CODE); + + $this->session->expects(static::once()) + ->method('getReordered') + ->willReturn(self::ORDER_ID); + $this->orderRepository->expects(static::once()) + ->method('get') + ->with(self::ORDER_ID) + ->willReturn($this->getOrderMock()); + + $this->paymentTokenManagement->expects(static::once()) + ->method('getByPaymentId') + ->with(self::ORDER_PAYMENT_ENTITY_ID) + ->willReturn(null); + + $this->filterBuilder->expects(static::once()) + ->method('setField') + ->with(PaymentTokenInterface::ENTITY_ID) + ->willReturnSelf(); + $this->filterBuilder->expects(static::never()) + ->method('setValue'); + + $this->searchCriteriaBuilder->expects(static::never()) + ->method('addFilters'); + + static::assertEmpty($this->configProvider->getTokensComponents(self::VAULT_PAYMENT_CODE)); + } + /** * Create mock object for store */ private function initStoreMock() { $this->store = $this->getMock(StoreInterface::class); - $this->store->expects(static::once()) + $this->store->expects(static::any()) ->method('getId') ->willReturn(self::STORE_ID); $this->storeManager = $this->getMock(StoreManagerInterface::class); - $this->storeManager->expects(static::once()) + $this->storeManager->expects(static::any()) ->method('getStore') ->with(null) ->willReturn($this->store); @@ -476,39 +488,37 @@ private function initStoreMock() */ private function getOrderMock() { - /** @var OrderInterface|MockObject $orderMock */ - $orderMock = $this->getMockBuilder(OrderInterface::class) + /** @var OrderInterface|MockObject $order */ + $order = $this->getMockBuilder(OrderInterface::class) ->getMockForAbstractClass(); - /** @var OrderPaymentInterface|MockObject $orderPaymentMock */ - $orderPaymentMock = $this->getMockBuilder(OrderPaymentInterface::class) + /** @var OrderPaymentInterface|MockObject $orderPayment */ + $orderPayment = $this->getMockBuilder(OrderPaymentInterface::class) ->getMockForAbstractClass(); - $orderMock->expects(static::once()) + $order->expects(static::once()) ->method('getPayment') - ->willReturn($orderPaymentMock); - $orderPaymentMock->expects(static::once()) + ->willReturn($orderPayment); + $orderPayment->expects(static::once()) ->method('getEntityId') ->willReturn(self::ORDER_PAYMENT_ENTITY_ID); - return $orderMock; + return $order; } /** * Get mock for token ui component provider * @param PaymentTokenInterface $token - * @return array + * @return TokenUiComponentInterface|MockObject */ private function getTokenUiComponentProvider($token) { $tokenUiComponent = $this->getMock(TokenUiComponentInterface::class); - - $tokenUiComponentProvider = $this->getMock(TokenUiComponentProviderInterface::class); - $tokenUiComponentProvider->expects(static::once()) + $this->tokenComponentProvider->expects(static::once()) ->method('getComponentForToken') ->with($token) ->willReturn($tokenUiComponent); - return [$tokenUiComponent, $tokenUiComponentProvider]; + return $tokenUiComponent; } /** diff --git a/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php b/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php index e64fff27ff14c..0053b0ef8b12d 100644 --- a/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php +++ b/app/code/Magento/Vault/Test/Unit/Model/Ui/TokensConfigProviderTest.php @@ -1,16 +1,15 @@ vaultPayment = $this->getMock(VaultPaymentInterface::class); + $this->objectManager = new ObjectManager($this); + $this->vaultPaymentList = $this->getMock(PaymentMethodListInterface::class); + $this->vaultPayment = $this->getMockForAbstractClass(VaultPaymentInterface::class); $this->storeManager = $this->getMock(StoreManagerInterface::class); $this->store = $this->getMock(StoreInterface::class); - $this->paymentDataHelper = $this->getMockBuilder(Data::class) - ->disableOriginalConstructor() - ->setMethods(['getStoreMethods']) - ->getMock(); - $this->objectManager = new ObjectManager($this); $this->customerTokenManagement = $this->getMockBuilder(CustomerTokenManagement::class) ->disableOriginalConstructor() ->getMock(); @@ -81,7 +77,7 @@ public function testGetConfig() $expectedConfig = [ 'payment' => [ 'vault' => [ - $vaultProviderCode . '_item_' . '0' => [ + $vaultProviderCode . '_' . '0' => [ 'config' => ['token_code' => 'code'], 'component' => 'Vendor_Module/js/vault_component' ] @@ -99,16 +95,12 @@ public function testGetConfig() $this->store->expects(static::once()) ->method('getId') ->willReturn($storeId); - - $this->paymentDataHelper->expects(static::once()) - ->method('getStoreMethods') + + $this->vaultPaymentList->expects(static::once()) + ->method('getActiveList') ->with($storeId) ->willReturn([$this->vaultPayment]); - $this->vaultPayment->expects(static::once()) - ->method('isActive') - ->with($storeId) - ->willReturn(true); $this->vaultPayment->expects(static::once()) ->method('getProviderCode') ->willReturn($vaultProviderCode); @@ -139,11 +131,10 @@ public function testGetConfig() $vaultProviderCode => $tokenUiComponentProvider ] ); - $this->objectManager->setBackwardCompatibleProperty( $configProvider, - 'paymentDataHelper', - $this->paymentDataHelper + 'vaultPaymentList', + $this->vaultPaymentList ); static::assertEquals($expectedConfig, $configProvider->getConfig()); diff --git a/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php b/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php index 7d0d8339ab2b1..3c7a7c2f6f033 100644 --- a/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php +++ b/app/code/Magento/Vault/Test/Unit/Model/Ui/VaultConfigProviderTest.php @@ -1,30 +1,24 @@ paymentDataHelper = $this->getMockBuilder(Data::class) - ->disableOriginalConstructor() - ->setMethods(['getStoreMethods']) - ->getMock(); - $this->vaultPayment = $this->getMockForAbstractClass(VaultPaymentInterface::class); $this->storeManager = $this->getMockForAbstractClass(StoreManagerInterface::class); $this->store = $this->getMockForAbstractClass(StoreInterface::class); $this->session = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() ->getMock(); + $this->vaultPaymentList = $this->getMock(PaymentMethodListInterface::class); $objectManager = new ObjectManager($this); $this->vaultConfigProvider = new VaultConfigProvider($this->storeManager, $this->session); $objectManager->setBackwardCompatibleProperty( $this->vaultConfigProvider, - 'paymentDataHelper', - $this->paymentDataHelper + 'vaultPaymentList', + $this->vaultPaymentList ); } @@ -94,16 +89,15 @@ public function testGetConfig($customerId, $vaultEnabled) $this->session->expects(static::once()) ->method('getCustomerId') ->willReturn($customerId); - $this->storeManager->expects(static::exactly(2)) + $this->storeManager->expects(static::once()) ->method('getStore') ->willReturn($this->store); - $this->store->expects(static::exactly(2)) + $this->store->expects(static::once()) ->method('getId') ->willReturn($storeId); - $this->paymentDataHelper->expects(static::once()) - ->method('getStoreMethods') - ->with($storeId) + $this->vaultPaymentList->expects(static::once()) + ->method('getActiveList') ->willReturn([$this->vaultPayment]); $this->vaultPayment->expects(static::once()) diff --git a/app/code/Magento/Vault/Test/Unit/Observer/AfterPaymentSaveObserverTest.php b/app/code/Magento/Vault/Test/Unit/Observer/AfterPaymentSaveObserverTest.php index f899d335f1397..c69af3bf32920 100644 --- a/app/code/Magento/Vault/Test/Unit/Observer/AfterPaymentSaveObserverTest.php +++ b/app/code/Magento/Vault/Test/Unit/Observer/AfterPaymentSaveObserverTest.php @@ -1,6 +1,6 @@ expects(static::once()) ->method('setAdditionalInformation') ->with( - Vault::TOKEN_METADATA_KEY, [ PaymentTokenInterface::CUSTOMER_ID => $customerId, PaymentTokenInterface::PUBLIC_HASH => $publicHash diff --git a/app/code/Magento/Vault/Test/Unit/Observer/VaultEnableAssignerTest.php b/app/code/Magento/Vault/Test/Unit/Observer/VaultEnableAssignerTest.php index 63b381a744b9b..cff5a0e354de9 100644 --- a/app/code/Magento/Vault/Test/Unit/Observer/VaultEnableAssignerTest.php +++ b/app/code/Magento/Vault/Test/Unit/Observer/VaultEnableAssignerTest.php @@ -1,6 +1,6 @@ storeManager = $this + ->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getStore']) + ->getMockForAbstractClass(); + $this->store = $this + ->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getId']) + ->getMockForAbstractClass(); + $this->vaultList = $this + ->getMockBuilder(\Magento\Vault\Api\PaymentMethodListInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getActiveList']) + ->getMockForAbstractClass(); + $this->paymentMethodList = $this + ->getMockBuilder(\Magento\Payment\Api\PaymentMethodListInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getActiveList']) + ->getMockForAbstractClass(); + $this->layoutProcessor = $this + ->getMockBuilder(\Magento\Checkout\Block\Checkout\LayoutProcessor::class) + ->disableOriginalConstructor() + ->setMethods(['process']) + ->getMockForAbstractClass(); + + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->plugin = $objectManagerHelper->getObject( + \Magento\Vault\Plugin\PaymentVaultConfigurationProcess::class, + [ + 'vaultPaymentList' => $this->vaultList, + 'paymentMethodList' => $this->paymentMethodList, + 'storeManager' => $this->storeManager + ] + ); + } + + /** + * @param array $jsLayout + * @param array $activeVaultList + * @param array $activePaymentList + * @param array $expectedResult + * @dataProvider beforeProcessDataProvider + */ + public function testBeforeProcess($jsLayout, $activeVaultList, $activePaymentList, $expectedResult) + { + $this->store->expects($this->once())->method('getId')->willReturn(1); + $this->storeManager->expects($this->once())->method('getStore')->willReturn($this->store); + $this->vaultList->expects($this->once())->method('getActiveList')->with(1)->willReturn($activeVaultList); + $this->paymentMethodList->expects($this->once()) + ->method('getActiveList') + ->with(1) + ->willReturn($activePaymentList); + $result = $this->plugin->beforeProcess($this->layoutProcessor, $jsLayout); + $this->assertEquals($result[0], $expectedResult); + } + + /** + * Data provider for BeforeProcess. + * + * @return array + */ + public function beforeProcessDataProvider() + { + $jsLayout['components']['checkout']['children']['steps']['children']['billing-step'] + ['children']['payment']['children']['renders']['children'] = [ + 'vault' => [ + 'methods' => [] + ], + 'braintree' => [ + 'methods' => [ + 'braintree_paypal' => [], + 'braintree' => [] + ] + ], + 'paypal-payments' => [ + 'methods' => [ + 'payflowpro' => [], + 'payflow_link' => [] + ] + ] + ]; + $result1['components']['checkout']['children']['steps']['children']['billing-step'] + ['children']['payment']['children']['renders']['children'] = []; + $result2['components']['checkout']['children']['steps']['children']['billing-step'] + ['children']['payment']['children']['renders']['children'] = [ + 'vault' => [ + 'methods' => [] + ], + 'braintree' => [ + 'methods' => [ + 'braintree_paypal' => [] + ] + ] + ]; + + $vaultPaymentMethod = $this + ->getMockBuilder(\Magento\Vault\Api\PaymentMethodListInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getCode', 'getProviderCode']) + ->getMockForAbstractClass(); + + $vaultPaymentMethod->expects($this->any())->method('getCode')->willReturn('braintree_paypal_vault'); + $vaultPaymentMethod->expects($this->any())->method('getProviderCode')->willReturn('braintree_paypal'); + + return [ + [$jsLayout, [], [], $result1], + [$jsLayout, [$vaultPaymentMethod], [$vaultPaymentMethod], $result2] + ]; + } +} diff --git a/app/code/Magento/Vault/composer.json b/app/code/Magento/Vault/composer.json index 74dd568e3b45e..b2edf040674d8 100644 --- a/app/code/Magento/Vault/composer.json +++ b/app/code/Magento/Vault/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-vault", "description": "", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/framework": "100.2.*", "magento/module-sales": "100.2.*", "magento/module-store": "100.2.*", diff --git a/app/code/Magento/Vault/etc/adminhtml/di.xml b/app/code/Magento/Vault/etc/adminhtml/di.xml index 9a19fa0fa0780..6c24cfcd7d8fa 100644 --- a/app/code/Magento/Vault/etc/adminhtml/di.xml +++ b/app/code/Magento/Vault/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ @@ -16,4 +16,4 @@ Magento\Backend\Model\Session\Quote - \ No newline at end of file + diff --git a/app/code/Magento/Vault/etc/config.xml b/app/code/Magento/Vault/etc/config.xml index 2bc3372ec2dc1..d7ca5c886d1cc 100644 --- a/app/code/Magento/Vault/etc/config.xml +++ b/app/code/Magento/Vault/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Vault/etc/di.xml b/app/code/Magento/Vault/etc/di.xml index e44e1da3e3d61..55a8913a826f5 100644 --- a/app/code/Magento/Vault/etc/di.xml +++ b/app/code/Magento/Vault/etc/di.xml @@ -1,7 +1,7 @@ @@ -11,6 +11,7 @@ + diff --git a/app/code/Magento/Vault/etc/events.xml b/app/code/Magento/Vault/etc/events.xml index d2fbe2049b553..dcdaa876902ad 100644 --- a/app/code/Magento/Vault/etc/events.xml +++ b/app/code/Magento/Vault/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Vault/etc/extension_attributes.xml b/app/code/Magento/Vault/etc/extension_attributes.xml index a39ea0c190b6c..abfb20767f9bb 100644 --- a/app/code/Magento/Vault/etc/extension_attributes.xml +++ b/app/code/Magento/Vault/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Vault/etc/frontend/di.xml b/app/code/Magento/Vault/etc/frontend/di.xml index d7f699faff53c..598a30aa1c73b 100644 --- a/app/code/Magento/Vault/etc/frontend/di.xml +++ b/app/code/Magento/Vault/etc/frontend/di.xml @@ -1,7 +1,7 @@ @@ -19,4 +19,8 @@ Magento\Customer\Model\Session + + + + diff --git a/app/code/Magento/Vault/etc/frontend/routes.xml b/app/code/Magento/Vault/etc/frontend/routes.xml index b132bc98445a8..ffa8e55afa700 100644 --- a/app/code/Magento/Vault/etc/frontend/routes.xml +++ b/app/code/Magento/Vault/etc/frontend/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Vault/etc/module.xml b/app/code/Magento/Vault/etc/module.xml index 740d93b4e133d..2e709dd6cfe11 100644 --- a/app/code/Magento/Vault/etc/module.xml +++ b/app/code/Magento/Vault/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Vault/registration.php b/app/code/Magento/Vault/registration.php index a7efe86dd4e7c..7132ef2bde9ca 100644 --- a/app/code/Magento/Vault/registration.php +++ b/app/code/Magento/Vault/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Vault/view/frontend/layout/customer_account.xml b/app/code/Magento/Vault/view/frontend/layout/customer_account.xml index 2042721d9d387..fe20e2923ffa3 100644 --- a/app/code/Magento/Vault/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Vault/view/frontend/layout/customer_account.xml @@ -1,17 +1,18 @@ - + vault/cards/listaction Stored Payment Methods + 160 diff --git a/app/code/Magento/Vault/view/frontend/layout/vault_cards_listaction.xml b/app/code/Magento/Vault/view/frontend/layout/vault_cards_listaction.xml index 5731fbd79154b..a41125414a424 100644 --- a/app/code/Magento/Vault/view/frontend/layout/vault_cards_listaction.xml +++ b/app/code/Magento/Vault/view/frontend/layout/vault_cards_listaction.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Vault/view/frontend/templates/cards_list.phtml b/app/code/Magento/Vault/view/frontend/templates/cards_list.phtml index 2dd08ca4c5c09..1982f85bd2243 100644 --- a/app/code/Magento/Vault/view/frontend/templates/cards_list.phtml +++ b/app/code/Magento/Vault/view/frontend/templates/cards_list.phtml @@ -1,6 +1,6 @@ @@ -49,4 +49,4 @@
    - \ No newline at end of file + diff --git a/app/code/Magento/Version/Controller/Index/Index.php b/app/code/Magento/Version/Controller/Index/Index.php index b97d1c9ba03e8..6fd45e15d913c 100644 --- a/app/code/Magento/Version/Controller/Index/Index.php +++ b/app/code/Magento/Version/Controller/Index/Index.php @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Version/etc/module.xml b/app/code/Magento/Version/etc/module.xml index 3642d966e65d9..8637a5d892368 100644 --- a/app/code/Magento/Version/etc/module.xml +++ b/app/code/Magento/Version/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Version/registration.php b/app/code/Magento/Version/registration.php index 735bec9afc224..ff790bc4808aa 100644 --- a/app/code/Magento/Version/registration.php +++ b/app/code/Magento/Version/registration.php @@ -1,6 +1,6 @@ cache = $cache; $this->configReader = $configReader; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -62,10 +74,10 @@ public function getServices() if (null === $this->services) { $services = $this->cache->load(self::CACHE_ID); if ($services && is_string($services)) { - $this->services = unserialize($services); + $this->services = $this->serializer->unserialize($services); } else { $this->services = $this->configReader->read(); - $this->cache->save(serialize($this->services), self::CACHE_ID); + $this->cache->save($this->serializer->serialize($this->services), self::CACHE_ID); } } return $this->services; diff --git a/app/code/Magento/Webapi/Model/Config/ClassReflector.php b/app/code/Magento/Webapi/Model/Config/ClassReflector.php index 81ba627959590..5a7b4c672c73a 100644 --- a/app/code/Magento/Webapi/Model/Config/ClassReflector.php +++ b/app/code/Magento/Webapi/Model/Config/ClassReflector.php @@ -1,6 +1,6 @@ config = $config; $this->cache = $cache; $this->classReflector = $classReflector; $this->typeProcessor = $typeProcessor; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -142,12 +152,18 @@ public function getServicesConfig() $servicesConfig = $this->cache->load(self::SERVICES_CONFIG_CACHE_ID); $typesData = $this->cache->load(self::REFLECTED_TYPES_CACHE_ID); if ($servicesConfig && is_string($servicesConfig) && $typesData && is_string($typesData)) { - $this->services = unserialize($servicesConfig); - $this->typeProcessor->setTypesData(unserialize($typesData)); + $this->services = $this->serializer->unserialize($servicesConfig); + $this->typeProcessor->setTypesData($this->serializer->unserialize($typesData)); } else { $this->services = $this->initServicesMetadata(); - $this->cache->save(serialize($this->services), self::SERVICES_CONFIG_CACHE_ID); - $this->cache->save(serialize($this->typeProcessor->getTypesData()), self::REFLECTED_TYPES_CACHE_ID); + $this->cache->save( + $this->serializer->serialize($this->services), + self::SERVICES_CONFIG_CACHE_ID + ); + $this->cache->save( + $this->serializer->serialize($this->typeProcessor->getTypesData()), + self::REFLECTED_TYPES_CACHE_ID + ); } } return $this->services; @@ -256,12 +272,18 @@ public function getRoutesConfig() $routesConfig = $this->cache->load(self::ROUTES_CONFIG_CACHE_ID); $typesData = $this->cache->load(self::REFLECTED_TYPES_CACHE_ID); if ($routesConfig && is_string($routesConfig) && $typesData && is_string($typesData)) { - $this->routes = unserialize($routesConfig); - $this->typeProcessor->setTypesData(unserialize($typesData)); + $this->routes = $this->serializer->unserialize($routesConfig); + $this->typeProcessor->setTypesData($this->serializer->unserialize($typesData)); } else { $this->routes = $this->initRoutesMetadata(); - $this->cache->save(serialize($this->routes), self::ROUTES_CONFIG_CACHE_ID); - $this->cache->save(serialize($this->typeProcessor->getTypesData()), self::REFLECTED_TYPES_CACHE_ID); + $this->cache->save( + $this->serializer->serialize($this->routes), + self::ROUTES_CONFIG_CACHE_ID + ); + $this->cache->save( + $this->serializer->serialize($this->typeProcessor->getTypesData()), + self::REFLECTED_TYPES_CACHE_ID + ); } } return $this->routes; diff --git a/app/code/Magento/Webapi/Model/Soap/Config.php b/app/code/Magento/Webapi/Model/Soap/Config.php index 41962981f17b2..f77b6d778beed 100644 --- a/app/code/Magento/Webapi/Model/Soap/Config.php +++ b/app/code/Magento/Webapi/Model/Soap/Config.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Webapi/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Webapi/Test/Unit/Model/ConfigTest.php new file mode 100644 index 0000000000000..143690acd0da7 --- /dev/null +++ b/app/code/Magento/Webapi/Test/Unit/Model/ConfigTest.php @@ -0,0 +1,96 @@ +webapiCacheMock = $this->getMock(\Magento\Webapi\Model\Cache\Type\Webapi::class, [], [], '', false); + $this->configReaderMock = $this->getMock(\Magento\Webapi\Model\Config\Reader::class, [], [], '', false); + $this->serializerMock = $this->getMock(SerializerInterface::class); + + $this->config = $objectManager->getObject( + Config::class, + [ + 'cache' => $this->webapiCacheMock, + 'configReader' => $this->configReaderMock, + 'serializer' => $this->serializerMock + ] + ); + } + + public function testGetServices() + { + $data = ['foo' => 'bar']; + $serializedData = 'serialized data'; + $this->webapiCacheMock->expects($this->once()) + ->method('load') + ->with(Config::CACHE_ID) + ->willReturn($serializedData); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($serializedData) + ->willReturn($data); + $this->config->getServices(); + $this->assertEquals($data, $this->config->getServices()); + } + + public function testGetServicesNoCache() + { + $data = ['foo' => 'bar']; + $serializedData = 'serialized data'; + $this->webapiCacheMock->expects($this->once()) + ->method('load') + ->with(Config::CACHE_ID) + ->willReturn(false); + $this->serializerMock->expects($this->never()) + ->method('unserialize'); + $this->configReaderMock->expects($this->once()) + ->method('read') + ->willReturn($data); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($data) + ->willReturn($serializedData); + $this->webapiCacheMock->expects($this->once()) + ->method('save') + ->with( + $serializedData, + Config::CACHE_ID + ); + + $this->config->getServices(); + $this->assertEquals($data, $this->config->getServices()); + } +} diff --git a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php index 4ab1609816332..93a25b69c527a 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/DataObjectProcessorTest.php @@ -1,11 +1,13 @@ $objectManager->getObject(\Magento\Framework\Reflection\TypeProcessor::class), ] ); + $serializerMock = $this->getMock(SerializerInterface::class); + $serializerMock->method('serialize') + ->willReturn('serializedData'); + $serializerMock->method('unserialize') + ->willReturn(['unserializedData']); + + $objectManager->setBackwardCompatibleProperty( + $methodsMapProcessor, + 'serializer', + $serializerMock + ); $this->dataObjectProcessor = $objectManager->getObject( \Magento\Framework\Reflection\DataObjectProcessor::class, [ diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php b/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php index d57a9d88824c3..5242e36daa406 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Files/TestDataInterface.php @@ -1,6 +1,6 @@ [ + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->configMock = $this->getMock(Config::class, [], [], '', false); + $this->cacheMock = $this->getMock(Webapi::class, [], [], '', false); + $this->classReflectorMock = $this->getMock(ClassReflector::class, [], [], '', false); + $this->typeProcessorMock = $this->getMock(TypeProcessor::class, [], [], '', false); + $this->serializerMock = $this->getMock(SerializerInterface::class); + + $this->serviceMetadata = $objectManager->getObject( + ServiceMetadata::class, + [ + 'config' => $this->configMock, + 'cache' => $this->cacheMock, + 'classReflector' => $this->classReflectorMock, + 'typeProcessor' => $this->typeProcessorMock, + 'serializer' => $this->serializerMock + ] + ); + } + + public function testGetServicesConfig() + { + $servicesConfig = ['foo' => 'bar']; + $typeData = ['bar' => 'foo']; + $serializedServicesConfig = 'serialized services config'; + $serializedTypeData = 'serialized type data'; + $this->cacheMock->expects($this->at(0)) + ->method('load') + ->with(ServiceMetadata::SERVICES_CONFIG_CACHE_ID) + ->willReturn($serializedServicesConfig); + $this->cacheMock->expects($this->at(1)) + ->method('load') + ->with(ServiceMetadata::REFLECTED_TYPES_CACHE_ID) + ->willReturn($serializedTypeData); + $this->serializerMock->expects($this->at(0)) + ->method('unserialize') + ->with($serializedServicesConfig) + ->willReturn($servicesConfig); + $this->serializerMock->expects($this->at(1)) + ->method('unserialize') + ->with($serializedTypeData) + ->willReturn($typeData); + $this->typeProcessorMock->expects($this->once()) + ->method('setTypesData') + ->with($typeData); + $this->serviceMetadata->getServicesConfig(); + $this->assertEquals($servicesConfig, $this->serviceMetadata->getServicesConfig()); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetServicesConfigNoCache() + { + $servicesConfig = [ + 'services' => [ + CustomerRepositoryInterface::class => [ + 'V1' => [ + 'methods' => [ + 'getById' => [ + 'resources' => [ + [ + 'Magento_Customer::customer', + ] + ], + 'secure' => false + ] + ] + ] + ] + ] + ]; + $methodsReflectionData = [ + 'getById' => [ + 'documentation' => 'Get customer by customer ID.', 'interface' => [ 'in' => [ 'parameters' => [ 'customerId' => [ - 'force' => true, - 'value' => '%customer_id%', - ], - 'requiredInputParameter' => [ + 'type' => 'int', 'required' => true, - ], - ], + 'documentation' => null + ] + ] ], 'out' => [ 'parameters' => [ - 'outputParameter' => [ - 'type' => 'string', + 'result' => [ + 'type' => 'CustomerDataCustomerInterface', + 'required' => true, + 'documentation' => null + ] + ] + ] + ] + ] + ]; + $servicesMetadata = [ + 'customerCustomerRepositoryV1' => [ + 'methods' => array_merge_recursive( + [ + 'getById' => [ + 'resources' => [ + [ + 'Magento_Customer::customer', + ], ], - ], + 'method' => 'getById', + 'inputRequired' => false, + 'isSecure' => false, + ] ], - ], - ], + $methodsReflectionData + ), + 'class' => CustomerRepositoryInterface::class, + 'description' => 'Customer CRUD interface.' + ] ]; - $classReflection = $this->getMock( - \Magento\Webapi\Model\Config\ClassReflector::class, - ['reflectClassMethods', 'extractClassDescription'], - [], - '', - false - ); - $classReflection->expects($this->any()) + $typeData = [ + 'CustomerDataCustomerInterface' => [ + 'documentation' => 'Customer interface.', + 'parameters' => [ + 'id' => [ + 'type' => 'int', + 'required' => false, + 'documentation' => 'Customer id' + ] + ] + ] + ]; + $serializedServicesConfig = 'serialized services config'; + $serializedTypeData = 'serialized type data'; + $this->cacheMock->expects($this->at(0)) + ->method('load') + ->with(ServiceMetadata::SERVICES_CONFIG_CACHE_ID) + ->willReturn(false); + $this->cacheMock->expects($this->at(1)) + ->method('load') + ->with(ServiceMetadata::REFLECTED_TYPES_CACHE_ID) + ->willReturn(false); + $this->serializerMock->expects($this->never()) + ->method('unserialize'); + $this->configMock->expects($this->once()) + ->method('getServices') + ->willReturn($servicesConfig); + $this->classReflectorMock->expects($this->once()) ->method('reflectClassMethods') - ->will($this->returnValue($interfaceParameters)); - $classReflection->expects($this->any()) + ->willReturn($methodsReflectionData); + $this->classReflectorMock->expects($this->once()) ->method('extractClassDescription') - ->will($this->returnValue('classDescription')); + ->with(CustomerRepositoryInterface::class) + ->willReturn('Customer CRUD interface.'); + $this->typeProcessorMock->expects($this->once()) + ->method('getTypesData') + ->willReturn($typeData); + $this->serializerMock->expects($this->at(0)) + ->method('serialize') + ->with($servicesMetadata) + ->willReturn($serializedServicesConfig); + $this->serializerMock->expects($this->at(1)) + ->method('serialize') + ->with($typeData) + ->willReturn($serializedTypeData); + $this->cacheMock->expects($this->at(2)) + ->method('save') + ->with( + $serializedServicesConfig, + ServiceMetadata::SERVICES_CONFIG_CACHE_ID + ); + $this->cacheMock->expects($this->at(3)) + ->method('save') + ->with( + $serializedTypeData, + ServiceMetadata::REFLECTED_TYPES_CACHE_ID + ); + $this->serviceMetadata->getServicesConfig(); + $this->assertEquals($servicesMetadata, $this->serviceMetadata->getServicesConfig()); + } + + public function testGetRoutesConfig() + { + $routesConfig = ['foo' => 'bar']; + $typeData = ['bar' => 'foo']; + $serializedRoutesConfig = 'serialized routes config'; + $serializedTypeData = 'serialized type data'; + $this->cacheMock->expects($this->at(0)) + ->method('load') + ->with(ServiceMetadata::ROUTES_CONFIG_CACHE_ID) + ->willReturn($serializedRoutesConfig); + $this->cacheMock->expects($this->at(1)) + ->method('load') + ->with(ServiceMetadata::REFLECTED_TYPES_CACHE_ID) + ->willReturn($serializedTypeData); + $this->serializerMock->expects($this->at(0)) + ->method('unserialize') + ->with($serializedRoutesConfig) + ->willReturn($routesConfig); + $this->serializerMock->expects($this->at(1)) + ->method('unserialize') + ->with($serializedTypeData) + ->willReturn($typeData); + $this->typeProcessorMock->expects($this->once()) + ->method('setTypesData') + ->with($typeData); + $this->serviceMetadata->getRoutesConfig(); + $this->assertEquals($routesConfig, $this->serviceMetadata->getRoutesConfig()); + } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetRoutesConfigNoCache() + { $servicesConfig = [ - 'services' => [\Magento\Customer\Api\AccountManagementInterface::class => [ - 'V1' => [ - 'methods' => [ - 'activateById' => [ - 'resources' => [ - [ - 'Magento_Customer::manage', - ], - ], - 'secure' => false, - ], - ], - ], - ], \Magento\Customer\Api\CustomerRepositoryInterface::class => [ + 'services' => [ + CustomerRepositoryInterface::class => [ 'V1' => [ 'methods' => [ 'getById' => [ 'resources' => [ [ 'Magento_Customer::customer', - ], + ] ], - 'secure' => false, - ], - ], - ], - ], + 'secure' => false + ] + ] + ] + ] ], 'routes' => [ - '/V1/customers/me/activate' => [ - 'PUT' => [ + '/V1/customers/:customerId' => [ + 'GET' => [ 'secure' => false, 'service' => [ - 'class' => \Magento\Customer\Api\AccountManagementInterface::class, - 'method' => 'activateById', + 'class' => CustomerRepositoryInterface::class, + 'method' => 'getById' ], 'resources' => [ - 'self' => true, + 'Magento_Customer::customer' => true ], + 'parameters' => [] + ] + ] + ], + 'class' => CustomerRepositoryInterface::class, + 'description' => 'Customer CRUD interface.', + ]; + $methodsReflectionData = [ + 'getById' => [ + 'documentation' => 'Get customer by customer ID.', + 'interface' => [ + 'in' => [ 'parameters' => [ 'customerId' => [ - 'force' => true, - 'value' => '%customer_id%', - ], - ], + 'type' => 'int', + 'required' => true, + 'documentation' => null + ] + ] ], - ], - '/V1/customers/:customerId' => [ - 'GET' => [ - 'secure' => false, - 'service' => [ - 'class' => \Magento\Customer\Api\CustomerRepositoryInterface::class, - 'method' => 'getById', - ], - 'resources' => [ - 'Magento_Customer::customer' => true, - ], + 'out' => [ 'parameters' => [ - ], + 'result' => [ + 'type' => 'CustomerDataCustomerInterface', + 'required' => true, + 'documentation' => null + ] + ] + ] + ] + ] + ]; + $routesMetadata = [ + 'customerCustomerRepositoryV1' => [ + 'methods' => array_merge_recursive( + [ + 'getById' => [ + 'resources' => [ + [ + 'Magento_Customer::customer', + ] + ], + 'method' => 'getById', + 'inputRequired' => false, + 'isSecure' => false, + ] ], + $methodsReflectionData + ), + 'routes' => [ + '/V1/customers/:customerId' => [ + 'GET' => [ + 'method' => 'getById', + 'parameters' => [] + ] + ] ], + 'class' => CustomerRepositoryInterface::class, + 'description' => 'Customer CRUD interface.' ] ]; - - /** - * @var $cacheMock \Magento\Webapi\Model\Cache\Type\Webapi - */ - $cacheMock = $this->getMockBuilder(\Magento\Webapi\Model\Cache\Type\Webapi::class) - ->disableOriginalConstructor() - ->getMock(); - - /** @var $readerMock \Magento\Webapi\Model\Config\Reader */ - $readerMock = $this->getMockBuilder(\Magento\Webapi\Model\Config\Reader::class) - ->disableOriginalConstructor() - ->getMock(); - $readerMock->expects($this->any())->method('read')->will($this->returnValue($servicesConfig)); - - /** @var $config \Magento\Webapi\Model\Config */ - $config = new \Magento\Webapi\Model\Config($cacheMock, $readerMock); - - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $typeProcessor = $objectManager->getObject(\Magento\Framework\Reflection\TypeProcessor::class); - - /** @var $config \Magento\Webapi\Model\ServiceMetadata */ - $this->serviceMetadata = new \Magento\Webapi\Model\ServiceMetadata( - $config, - $cacheMock, - $classReflection, - $typeProcessor - ); - - parent::setUp(); + $typeData = [ + 'CustomerDataCustomerInterface' => [ + 'documentation' => 'Customer interface.', + 'parameters' => [ + 'id' => [ + 'type' => 'int', + 'required' => false, + 'documentation' => 'Customer id' + ] + ] + ] + ]; + $serializedRoutesConfig = 'serialized routes config'; + $serializedTypeData = 'serialized type data'; + $this->cacheMock->expects($this->at(0)) + ->method('load') + ->with(ServiceMetadata::ROUTES_CONFIG_CACHE_ID) + ->willReturn(false); + $this->cacheMock->expects($this->at(1)) + ->method('load') + ->with(ServiceMetadata::REFLECTED_TYPES_CACHE_ID) + ->willReturn(false); + $this->serializerMock->expects($this->never()) + ->method('unserialize'); + $this->configMock->expects($this->exactly(2)) + ->method('getServices') + ->willReturn($servicesConfig); + $this->classReflectorMock->expects($this->once()) + ->method('reflectClassMethods') + ->willReturn($methodsReflectionData); + $this->classReflectorMock->expects($this->once()) + ->method('extractClassDescription') + ->with(CustomerRepositoryInterface::class) + ->willReturn('Customer CRUD interface.'); + $this->typeProcessorMock->expects($this->exactly(2)) + ->method('getTypesData') + ->willReturn($typeData); + $this->serializerMock->expects($this->at(2)) + ->method('serialize') + ->with($routesMetadata) + ->willReturn($serializedRoutesConfig); + $this->serializerMock->expects($this->at(3)) + ->method('serialize') + ->with($typeData) + ->willReturn($serializedTypeData); + $this->cacheMock->expects($this->at(6)) + ->method('save') + ->with( + $serializedRoutesConfig, + ServiceMetadata::ROUTES_CONFIG_CACHE_ID + ); + $this->cacheMock->expects($this->at(7)) + ->method('save') + ->with( + $serializedTypeData, + ServiceMetadata::REFLECTED_TYPES_CACHE_ID + ); + $this->serviceMetadata->getRoutesConfig(); + $this->assertEquals($routesMetadata, $this->serviceMetadata->getRoutesConfig()); } /** - * Test identifying service name including subservices using class name. - * - * @dataProvider serviceNameDataProvider + * @dataProvider getServiceNameDataProvider */ public function testGetServiceName($className, $version, $preserveVersion, $expected) { - $actual = $this->serviceMetadata->getServiceName($className, $version, $preserveVersion); - $this->assertEquals($expected, $actual); + $this->assertEquals( + $expected, + $this->serviceMetadata->getServiceName($className, $version, $preserveVersion) + ); } /** - * Dataprovider for testGetServiceName - * * @return string */ - public function serviceNameDataProvider() + public function getServiceNameDataProvider() { return [ - [\Magento\Customer\Api\AccountManagementInterface::class, 'V1', false, 'customerAccountManagement'], - [\Magento\Customer\Api\AddressRepositoryInterface::class, 'V1', true, 'customerAddressRepositoryV1'], + [ + \Magento\Customer\Api\AccountManagementInterface::class, + 'V1', + false, + 'customerAccountManagement' + ], + [ + \Magento\Customer\Api\AddressRepositoryInterface::class, + 'V1', + true, + 'customerAddressRepositoryV1' + ], ]; } /** * @expectedException \InvalidArgumentException - * @dataProvider dataProviderForTestGetServiceNameInvalidName + * @dataProvider getServiceNameInvalidNameDataProvider */ public function testGetServiceNameInvalidName($interfaceClassName, $version) { @@ -189,111 +452,18 @@ public function testGetServiceNameInvalidName($interfaceClassName, $version) } /** - * Dataprovider for testGetServiceNameInvalidName - * * @return string */ - public function dataProviderForTestGetServiceNameInvalidName() + public function getServiceNameInvalidNameDataProvider() { return [ - ['BarV1Interface', 'V1'], // Missed vendor, module, 'Service' + ['BarV1Interface', 'V1'], // Missed vendor, module and Service ['Service\\V1Interface', 'V1'], // Missed vendor and module ['Magento\\Foo\\Service\\BarVxInterface', 'V1'], // Version number should be a number - ['Magento\\Foo\\Service\\BarInterface', 'V1'], // Version missed - ['Magento\\Foo\\Service\\BarV1', 'V1'], // 'Interface' missed - ['Foo\\Service\\BarV1Interface', 'V1'], // Module missed - ['Foo\\BarV1Interface', 'V1'] // Module and 'Service' missed - ]; - } - - public function testGetServiceMetadata() - { - $expectedResult = [ - 'methods' => [ - 'activateById' => [ - 'method' => 'activateById', - 'inputRequired' => '', - 'isSecure' => '', - 'resources' => [['Magento_Customer::manage']], - 'interface' => [ - 'in' => [ - 'parameters' => [ - 'customerId' => [ - 'force' => true, - 'value' => '%customer_id%', - ], - 'requiredInputParameter' => [ - 'required' => true, - ], - ], - ], - 'out' => [ - 'parameters' => [ - 'outputParameter' => [ - 'type' => 'string', - ], - ], - ], - ], - ], - ], - 'class' => \Magento\Customer\Api\AccountManagementInterface::class, - 'description' => 'classDescription', + ['Magento\\Foo\\Service\\BarInterface', 'V1'], // Missed version + ['Magento\\Foo\\Service\\BarV1', 'V1'], // Missed Interface + ['Foo\\Service\\BarV1Interface', 'V1'], // Missed module + ['Foo\\BarV1Interface', 'V1'] // Missed module and Service ]; - $result = $this->serviceMetadata->getServiceMetadata('customerAccountManagementV1'); - $this->assertEquals($expectedResult, $result); - } - - public function testGetRouteMetadata() - { - $expectedResult = [ - 'methods' => [ - 'activateById' => [ - 'method' => 'activateById', - 'inputRequired' => '', - 'isSecure' => '', - 'resources' => [['Magento_Customer::manage']], - 'interface' => [ - 'in' => [ - 'parameters' => [ - 'customerId' => [ - 'force' => true, - 'value' => '%customer_id%', - ], - 'requiredInputParameter' => [ - 'required' => true, - ], - ], - ], - 'out' => [ - 'parameters' => [ - 'outputParameter' => [ - 'type' => 'string', - ], - ], - ], - ], - ], - ], - 'class' => \Magento\Customer\Api\AccountManagementInterface::class, - 'description' => 'classDescription', - 'routes' => [ - '/V1/customers/me/activate' => [ - 'PUT' => [ - 'method' => 'activateById', - 'parameters' => [ - 'customerId' => [ - 'force' => true, - 'value' => '%customer_id%' - ] - ] - ] - ] - ] - ]; - $result = $this->serviceMetadata->getRouteMetadata('customerAccountManagementV1'); - $this->assertEquals($expectedResult, $result); } } - -require_once realpath(__DIR__ . '/../_files/test_interfaces.php'); diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Soap/ConfigTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Soap/ConfigTest.php deleted file mode 100644 index aa5d1a7bfab7e..0000000000000 --- a/app/code/Magento/Webapi/Test/Unit/Model/Soap/ConfigTest.php +++ /dev/null @@ -1,166 +0,0 @@ -objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - - $typeProcessor = $this->objectManager->getObject(\Magento\Framework\Reflection\TypeProcessor::class); - - $objectManagerMock = $this->getMockBuilder( - \Magento\Framework\App\ObjectManager::class - )->disableOriginalConstructor()->getMock(); - - $classReflection = $this->getMock( - \Magento\Webapi\Model\Config\ClassReflector::class, - ['reflectClassMethods'], - ['_typeProcessor' => $typeProcessor], - '' - ); - $classReflection->expects($this->any())->method('reflectClassMethods')->will($this->returnValue([])); - - $servicesConfig = [ - 'services' => [\Magento\Customer\Api\AccountManagementInterface::class => [ - 'V1' => [ - 'methods' => [ - 'activate' => [ - 'resources' => [ - [ - 'Magento_Customer::manage', - ], - ], - 'secure' => false, - ], - ], - ], - ], \Magento\Customer\Api\CustomerRepositoryInterface::class => [ - 'V1' => [ - 'methods' => [ - 'getById' => [ - 'resources' => [ - [ - 'Magento_Customer::customer', - ], - ], - 'secure' => false, - ], - ], - ], - ], - ], - ]; - - /** - * @var $registryMock \Magento\Framework\Registry - */ - $registryMock = $this->getMockBuilder(\Magento\Framework\Registry::class) - ->disableOriginalConstructor() - ->getMock(); - - /** - * @var $cacheMock \Magento\Webapi\Model\Cache\Type\Webapi - */ - $cacheMock = $this->getMockBuilder(\Magento\Webapi\Model\Cache\Type\Webapi::class) - ->disableOriginalConstructor() - ->getMock(); - - /** @var $readerMock \Magento\Webapi\Model\Config\Reader */ - $readerMock = $this->getMockBuilder(\Magento\Webapi\Model\Config\Reader::class) - ->disableOriginalConstructor() - ->getMock(); - $readerMock->expects($this->any())->method('read')->will($this->returnValue($servicesConfig)); - - /** @var $config \Magento\Webapi\Model\Config */ - $config = new \Magento\Webapi\Model\Config($cacheMock, $readerMock); - - /** @var $config \Magento\Webapi\Model\ServiceMetadata */ - $serviceMetadata = new \Magento\Webapi\Model\ServiceMetadata( - $config, - $cacheMock, - $classReflection, - $typeProcessor); - - $this->_soapConfig = $this->objectManager->getObject( - \Magento\Webapi\Model\Soap\Config::class, - [ - 'objectManager' => $objectManagerMock, - 'registry' => $registryMock, - 'serviceMetadata' => $serviceMetadata, - ] - ); - parent::setUp(); - } - - public function testGetRequestedSoapServices() - { - $expectedResult = [ - 'customerAccountManagementV1' => - [ - 'methods' => [ - 'activate' => [ - 'method' => 'activate', - 'inputRequired' => '', - 'isSecure' => '', - 'resources' => [['Magento_Customer::manage']], - ], - ], - 'class' => \Magento\Customer\Api\AccountManagementInterface::class, - 'description' => 'Interface for managing customers accounts.', - ], - ]; - - $result = $this->_soapConfig->getRequestedSoapServices( - ['customerAccountManagementV1', 'moduleBarV2', 'moduleBazV1'] - ); - - $this->assertEquals($expectedResult, $result); - } - - public function testGetServiceMethodInfo() - { - $expectedResult = [ - 'class' => \Magento\Customer\Api\CustomerRepositoryInterface::class, - 'method' => 'getById', - 'isSecure' => false, - 'resources' => [['Magento_Customer::customer']], - ]; - $methodInfo = $this->_soapConfig->getServiceMethodInfo( - 'customerCustomerRepositoryV1GetById', - ['customerCustomerRepositoryV1', 'moduleBazV1'] - ); - $this->assertEquals($expectedResult, $methodInfo); - } - - public function testGetSoapOperation() - { - $expectedResult = 'customerAccountManagementV1Activate'; - $soapOperation = $this->_soapConfig - ->getSoapOperation(\Magento\Customer\Api\AccountManagementInterface::class, 'activate', 'V1'); - $this->assertEquals($expectedResult, $soapOperation); - } -} - -require_once realpath(__DIR__ . '/../../_files/test_interfaces.php'); diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Soap/FaultTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Soap/FaultTest.php index 1be772c2e5062..1e419686049d0 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Soap/FaultTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Soap/FaultTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Webapi/Test/Unit/Model/_files/acl.xsd b/app/code/Magento/Webapi/Test/Unit/Model/_files/acl.xsd index e79fbd2a5c3a8..367be30cd8ab6 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/_files/acl.xsd +++ b/app/code/Magento/Webapi/Test/Unit/Model/_files/acl.xsd @@ -3,7 +3,7 @@ /** * Structure description for acl.xml ACL resource files. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/app/code/Magento/Webapi/Test/Unit/_files/soap_fault/soap_fault_expected_xmls.php b/app/code/Magento/Webapi/Test/Unit/_files/soap_fault/soap_fault_expected_xmls.php index 07645c1bff548..adbf030f9e3fb 100644 --- a/app/code/Magento/Webapi/Test/Unit/_files/soap_fault/soap_fault_expected_xmls.php +++ b/app/code/Magento/Webapi/Test/Unit/_files/soap_fault/soap_fault_expected_xmls.php @@ -2,7 +2,7 @@ /** * The list of all expected soap fault XMLs. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ return [ diff --git a/app/code/Magento/Webapi/Test/Unit/_files/test_interfaces.php b/app/code/Magento/Webapi/Test/Unit/_files/test_interfaces.php deleted file mode 100644 index 288a747cefd89..0000000000000 --- a/app/code/Magento/Webapi/Test/Unit/_files/test_interfaces.php +++ /dev/null @@ -1,31 +0,0 @@ - diff --git a/app/code/Magento/Webapi/etc/cache.xml b/app/code/Magento/Webapi/etc/cache.xml index 30a0ee8b6351b..31f995e9433bc 100644 --- a/app/code/Magento/Webapi/etc/cache.xml +++ b/app/code/Magento/Webapi/etc/cache.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Webapi/etc/di.xml b/app/code/Magento/Webapi/etc/di.xml index 484423d010f1f..fc8d4a31f2f04 100644 --- a/app/code/Magento/Webapi/etc/di.xml +++ b/app/code/Magento/Webapi/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Webapi/etc/frontend/routes.xml b/app/code/Magento/Webapi/etc/frontend/routes.xml index e5da2b5beb27d..c4d4d29d80bf4 100644 --- a/app/code/Magento/Webapi/etc/frontend/routes.xml +++ b/app/code/Magento/Webapi/etc/frontend/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Webapi/etc/module.xml b/app/code/Magento/Webapi/etc/module.xml index f49a6a0788114..05fe801020c78 100644 --- a/app/code/Magento/Webapi/etc/module.xml +++ b/app/code/Magento/Webapi/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Webapi/etc/webapi.xsd b/app/code/Magento/Webapi/etc/webapi.xsd index d85fce51d2f23..da56d6468b73a 100644 --- a/app/code/Magento/Webapi/etc/webapi.xsd +++ b/app/code/Magento/Webapi/etc/webapi.xsd @@ -3,7 +3,7 @@ /** * Structure description for webapi.xml configuration files. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/app/code/Magento/Webapi/etc/webapi_rest/di.xml b/app/code/Magento/Webapi/etc/webapi_rest/di.xml index 26a32e6a96ae1..9c93b1bfb5cb9 100644 --- a/app/code/Magento/Webapi/etc/webapi_rest/di.xml +++ b/app/code/Magento/Webapi/etc/webapi_rest/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Webapi/etc/webapi_soap/di.xml b/app/code/Magento/Webapi/etc/webapi_soap/di.xml index f52888a8c6445..565277d9b78d8 100644 --- a/app/code/Magento/Webapi/etc/webapi_soap/di.xml +++ b/app/code/Magento/Webapi/etc/webapi_soap/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Webapi/registration.php b/app/code/Magento/Webapi/registration.php index 1d5f8ba2a52db..17a879648daea 100644 --- a/app/code/Magento/Webapi/registration.php +++ b/app/code/Magento/Webapi/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Webapi/view/adminhtml/layout/adminhtml_integration_permissionsdialog.xml b/app/code/Magento/Webapi/view/adminhtml/layout/adminhtml_integration_permissionsdialog.xml index 46e3519e6227e..91a978b647ba1 100644 --- a/app/code/Magento/Webapi/view/adminhtml/layout/adminhtml_integration_permissionsdialog.xml +++ b/app/code/Magento/Webapi/view/adminhtml/layout/adminhtml_integration_permissionsdialog.xml @@ -3,7 +3,7 @@ /** * Tab for integration activation permissions popup. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/app/code/Magento/WebapiSecurity/Model/Plugin/AnonymousResourceSecurity.php b/app/code/Magento/WebapiSecurity/Model/Plugin/AnonymousResourceSecurity.php index 204ddbdc59906..b0268518b636b 100644 --- a/app/code/Magento/WebapiSecurity/Model/Plugin/AnonymousResourceSecurity.php +++ b/app/code/Magento/WebapiSecurity/Model/Plugin/AnonymousResourceSecurity.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/WebapiSecurity/etc/config.xml b/app/code/Magento/WebapiSecurity/etc/config.xml index df03d23d607be..d80ac4a164d16 100644 --- a/app/code/Magento/WebapiSecurity/etc/config.xml +++ b/app/code/Magento/WebapiSecurity/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/WebapiSecurity/etc/di.xml b/app/code/Magento/WebapiSecurity/etc/di.xml index 88fb85ad1feb9..22c06dfdf71d8 100644 --- a/app/code/Magento/WebapiSecurity/etc/di.xml +++ b/app/code/Magento/WebapiSecurity/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/WebapiSecurity/etc/module.xml b/app/code/Magento/WebapiSecurity/etc/module.xml index 8eb00fc7929e0..0d016c29dd755 100644 --- a/app/code/Magento/WebapiSecurity/etc/module.xml +++ b/app/code/Magento/WebapiSecurity/etc/module.xml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/WebapiSecurity/registration.php b/app/code/Magento/WebapiSecurity/registration.php index 886c73be0a230..1d671f658cbf8 100644 --- a/app/code/Magento/WebapiSecurity/registration.php +++ b/app/code/Magento/WebapiSecurity/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Weee/etc/adminhtml/events.xml b/app/code/Magento/Weee/etc/adminhtml/events.xml index 815a1693d3493..00ec05e9f4e4a 100644 --- a/app/code/Magento/Weee/etc/adminhtml/events.xml +++ b/app/code/Magento/Weee/etc/adminhtml/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/adminhtml/system.xml b/app/code/Magento/Weee/etc/adminhtml/system.xml index d3913e1b1890b..cc97f910e7ccd 100644 --- a/app/code/Magento/Weee/etc/adminhtml/system.xml +++ b/app/code/Magento/Weee/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/config.xml b/app/code/Magento/Weee/etc/config.xml index 5306ff85027f2..f6d9676c6ee99 100644 --- a/app/code/Magento/Weee/etc/config.xml +++ b/app/code/Magento/Weee/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/di.xml b/app/code/Magento/Weee/etc/di.xml index cd130ab9b8298..084a5eefc7f73 100644 --- a/app/code/Magento/Weee/etc/di.xml +++ b/app/code/Magento/Weee/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/events.xml b/app/code/Magento/Weee/etc/events.xml index 84b6f2fc58dee..46ac52f516dfd 100644 --- a/app/code/Magento/Weee/etc/events.xml +++ b/app/code/Magento/Weee/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/fieldset.xml b/app/code/Magento/Weee/etc/fieldset.xml index b92ff01b38267..30d4fcd44bb27 100644 --- a/app/code/Magento/Weee/etc/fieldset.xml +++ b/app/code/Magento/Weee/etc/fieldset.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/frontend/di.xml b/app/code/Magento/Weee/etc/frontend/di.xml index 009cfb820b01e..f31c718b91ee6 100644 --- a/app/code/Magento/Weee/etc/frontend/di.xml +++ b/app/code/Magento/Weee/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/frontend/events.xml b/app/code/Magento/Weee/etc/frontend/events.xml index f717191fe1411..de485427d7c43 100644 --- a/app/code/Magento/Weee/etc/frontend/events.xml +++ b/app/code/Magento/Weee/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/module.xml b/app/code/Magento/Weee/etc/module.xml index c49c21015cbda..8c59e20d3803e 100644 --- a/app/code/Magento/Weee/etc/module.xml +++ b/app/code/Magento/Weee/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/pdf.xml b/app/code/Magento/Weee/etc/pdf.xml index 2b03811b78f0c..9d34b8b0628c5 100644 --- a/app/code/Magento/Weee/etc/pdf.xml +++ b/app/code/Magento/Weee/etc/pdf.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/etc/sales.xml b/app/code/Magento/Weee/etc/sales.xml index 6a97c85a6130a..c2c484184b804 100644 --- a/app/code/Magento/Weee/etc/sales.xml +++ b/app/code/Magento/Weee/etc/sales.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/registration.php b/app/code/Magento/Weee/registration.php index aba23508ce753..8fa46f234ff31 100644 --- a/app/code/Magento/Weee/registration.php +++ b/app/code/Magento/Weee/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_creditmemo_item_price.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_creditmemo_item_price.xml index b0d8f9058a909..8db6ad29a9d72 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_creditmemo_item_price.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_creditmemo_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_invoice_item_price.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_invoice_item_price.xml index 3369c069752ef..bd78d50eb2375 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_invoice_item_price.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_invoice_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_create_item_price.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_create_item_price.xml index 8fafe1fe29c6f..62c6e2f11a7b7 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_create_item_price.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_create_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_new.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_new.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_new.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_view.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_view.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_view.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_creditmemo_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_new.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_new.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_new.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_new.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_updateqty.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_updateqty.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_updateqty.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_updateqty.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_view.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_view.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_view.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_invoice_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_item_price.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_item_price.xml index e3f350094a09b..38279d31b0500 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_item_price.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_view.xml b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_view.xml index a13f0f839c237..1c2f825d85dd5 100644 --- a/app/code/Magento/Weee/view/adminhtml/layout/sales_order_view.xml +++ b/app/code/Magento/Weee/view/adminhtml/layout/sales_order_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/requirejs-config.js b/app/code/Magento/Weee/view/adminhtml/requirejs-config.js index 9bd949b1ad3aa..1d5a3a6d02502 100644 --- a/app/code/Magento/Weee/view/adminhtml/requirejs-config.js +++ b/app/code/Magento/Weee/view/adminhtml/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -9,4 +9,4 @@ var config = { fptAttribute: 'Magento_Weee/js/fpt-attribute' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Weee/view/adminhtml/templates/items/price/row.phtml b/app/code/Magento/Weee/view/adminhtml/templates/items/price/row.phtml index 298b61ca0500d..533af55c40525 100644 --- a/app/code/Magento/Weee/view/adminhtml/templates/items/price/row.phtml +++ b/app/code/Magento/Weee/view/adminhtml/templates/items/price/row.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Weee/view/adminhtml/web/js/fpt-attribute.js b/app/code/Magento/Weee/view/adminhtml/web/js/fpt-attribute.js index d95f07076e0d4..7b00a5e891612 100644 --- a/app/code/Magento/Weee/view/adminhtml/web/js/fpt-attribute.js +++ b/app/code/Magento/Weee/view/adminhtml/web/js/fpt-attribute.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Weee/view/adminhtml/web/js/fpt-group.js b/app/code/Magento/Weee/view/adminhtml/web/js/fpt-group.js index 921a54ad09964..dbff56ac61fab 100644 --- a/app/code/Magento/Weee/view/adminhtml/web/js/fpt-group.js +++ b/app/code/Magento/Weee/view/adminhtml/web/js/fpt-group.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Weee/view/adminhtml/web/js/regions-tax-select.js b/app/code/Magento/Weee/view/adminhtml/web/js/regions-tax-select.js index 7034cc5e6bd73..189a8ac2be3ec 100644 --- a/app/code/Magento/Weee/view/adminhtml/web/js/regions-tax-select.js +++ b/app/code/Magento/Weee/view/adminhtml/web/js/regions-tax-select.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Weee/view/base/layout/catalog_product_prices.xml b/app/code/Magento/Weee/view/base/layout/catalog_product_prices.xml index c5d5b6735c58d..bae712d0a6aef 100644 --- a/app/code/Magento/Weee/view/base/layout/catalog_product_prices.xml +++ b/app/code/Magento/Weee/view/base/layout/catalog_product_prices.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml b/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml index a249b07b5fba8..21dfc2602ae86 100644 --- a/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml +++ b/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/checkout_index_index.xml b/app/code/Magento/Weee/view/frontend/layout/checkout_index_index.xml index b5e3c96796b86..7538f5780b941 100644 --- a/app/code/Magento/Weee/view/frontend/layout/checkout_index_index.xml +++ b/app/code/Magento/Weee/view/frontend/layout/checkout_index_index.xml @@ -1,7 +1,7 @@ @@ -59,4 +59,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Weee/view/frontend/layout/checkout_item_price_renderers.xml b/app/code/Magento/Weee/view/frontend/layout/checkout_item_price_renderers.xml index 3e562587ff902..bd87ee64a6f86 100644 --- a/app/code/Magento/Weee/view/frontend/layout/checkout_item_price_renderers.xml +++ b/app/code/Magento/Weee/view/frontend/layout/checkout_item_price_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/default.xml b/app/code/Magento/Weee/view/frontend/layout/default.xml index 7509438df2553..e01b48cc71b11 100644 --- a/app/code/Magento/Weee/view/frontend/layout/default.xml +++ b/app/code/Magento/Weee/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_email_item_price.xml b/app/code/Magento/Weee/view/frontend/layout/sales_email_item_price.xml index 53c62ea18d6ce..a9aa5d63beb73 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_email_item_price.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_email_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_email_order_creditmemo_items.xml b/app/code/Magento/Weee/view/frontend/layout/sales_email_order_creditmemo_items.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_email_order_creditmemo_items.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_email_order_creditmemo_items.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_email_order_invoice_items.xml b/app/code/Magento/Weee/view/frontend/layout/sales_email_order_invoice_items.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_email_order_invoice_items.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_email_order_invoice_items.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_email_order_items.xml b/app/code/Magento/Weee/view/frontend/layout/sales_email_order_items.xml index a13f0f839c237..1c2f825d85dd5 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_email_order_items.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_email_order_items.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_guest_creditmemo.xml b/app/code/Magento/Weee/view/frontend/layout/sales_guest_creditmemo.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_guest_creditmemo.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_guest_creditmemo.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_guest_invoice.xml b/app/code/Magento/Weee/view/frontend/layout/sales_guest_invoice.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_guest_invoice.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_guest_invoice.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_guest_print.xml b/app/code/Magento/Weee/view/frontend/layout/sales_guest_print.xml index a13f0f839c237..1c2f825d85dd5 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_guest_print.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_guest_print.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_guest_printcreditmemo.xml b/app/code/Magento/Weee/view/frontend/layout/sales_guest_printcreditmemo.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_guest_printcreditmemo.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_guest_printcreditmemo.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_guest_printinvoice.xml b/app/code/Magento/Weee/view/frontend/layout/sales_guest_printinvoice.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_guest_printinvoice.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_guest_printinvoice.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_guest_view.xml b/app/code/Magento/Weee/view/frontend/layout/sales_guest_view.xml index a13f0f839c237..1c2f825d85dd5 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_guest_view.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_guest_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_order_creditmemo.xml b/app/code/Magento/Weee/view/frontend/layout/sales_order_creditmemo.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_order_creditmemo.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_order_creditmemo.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_order_invoice.xml b/app/code/Magento/Weee/view/frontend/layout/sales_order_invoice.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_order_invoice.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_order_invoice.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_order_item_price.xml b/app/code/Magento/Weee/view/frontend/layout/sales_order_item_price.xml index d4620fc4d4818..90473aa072d01 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_order_item_price.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_order_item_price.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_order_print.xml b/app/code/Magento/Weee/view/frontend/layout/sales_order_print.xml index a13f0f839c237..1c2f825d85dd5 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_order_print.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_order_print.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_order_printcreditmemo.xml b/app/code/Magento/Weee/view/frontend/layout/sales_order_printcreditmemo.xml index 33fa9b0ee47d4..b80a6ab9627aa 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_order_printcreditmemo.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_order_printcreditmemo.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_order_printinvoice.xml b/app/code/Magento/Weee/view/frontend/layout/sales_order_printinvoice.xml index 94345af8b8507..17ae336776d5c 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_order_printinvoice.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_order_printinvoice.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/layout/sales_order_view.xml b/app/code/Magento/Weee/view/frontend/layout/sales_order_view.xml index a13f0f839c237..1c2f825d85dd5 100644 --- a/app/code/Magento/Weee/view/frontend/layout/sales_order_view.xml +++ b/app/code/Magento/Weee/view/frontend/layout/sales_order_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Weee/view/frontend/requirejs-config.js b/app/code/Magento/Weee/view/frontend/requirejs-config.js index c00c77a2486df..7719e9068413f 100644 --- a/app/code/Magento/Weee/view/frontend/requirejs-config.js +++ b/app/code/Magento/Weee/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/code/Magento/Weee/view/frontend/templates/checkout/cart/item/price/sidebar.phtml b/app/code/Magento/Weee/view/frontend/templates/checkout/cart/item/price/sidebar.phtml index 57727051abf7f..ab05ed0e2f409 100644 --- a/app/code/Magento/Weee/view/frontend/templates/checkout/cart/item/price/sidebar.phtml +++ b/app/code/Magento/Weee/view/frontend/templates/checkout/cart/item/price/sidebar.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_incl_tax.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_incl_tax.html index 5aa158adf4f64..c835683c956a2 100644 --- a/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_incl_tax.html +++ b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/item/price/row_incl_tax.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/weee.html b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/weee.html index 0810bdba5dd40..5106257704c1a 100644 --- a/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/weee.html +++ b/app/code/Magento/Weee/view/frontend/web/template/checkout/summary/weee.html @@ -1,6 +1,6 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget.php b/app/code/Magento/Widget/Block/Adminhtml/Widget.php index 2765b00897ec4..01cbe16ea6ff9 100644 --- a/app/code/Magento/Widget/Block/Adminhtml/Widget.php +++ b/app/code/Magento/Widget/Block/Adminhtml/Widget.php @@ -1,6 +1,6 @@ serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + } + + /** + * Encode widget conditions to be used with WYSIWIG. * * @param array $value * @return string */ public function encode(array $value) { - $value = str_replace(['{', '}', '"', '\\'], ['[', ']', '`', '|'], serialize($value)); + $value = str_replace(['{', '}', '"', '\\\\'], ['[', ']', '`', '|'], $this->serializer->serialize($value)); return $value; } /** - * Decode previously encoded widget conditions + * Decode previously encoded widget conditions. * * @param string $value * @return array */ public function decode($value) { - $value = str_replace(['[', ']', '`', '|'], ['{', '}', '"', '\\'], $value); - $value = unserialize($value); + $value = str_replace(['[', ']', '`', '|'], ['{', '}', '"', '\\\\'], $value); + $value = $this->serializer->unserialize($value); return $value; } } diff --git a/app/code/Magento/Widget/Model/Config/Converter.php b/app/code/Magento/Widget/Model/Config/Converter.php index fe65c29829e69..9059d0395222d 100644 --- a/app/code/Magento/Widget/Model/Config/Converter.php +++ b/app/code/Magento/Widget/Model/Config/Converter.php @@ -1,6 +1,6 @@ fetchRow($select, $bind); if (is_array($widget)) { if ($widget['parameters']) { - $widget['parameters'] = unserialize($widget['parameters']); + $widget['parameters'] = $this->getSerializer()->unserialize($widget['parameters']); } return $widget; } diff --git a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance.php b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance.php index 2fe5b13854d25..ad0e88aca528f 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance.php @@ -1,6 +1,6 @@ _resourceModel = $widgetResourceModel; + $this->_resourceModel = $widgetResourceModel->create(); } /** diff --git a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Themes.php b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Themes.php new file mode 100644 index 0000000000000..78bf815374c47 --- /dev/null +++ b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Themes.php @@ -0,0 +1,41 @@ +themeCollectionFactory = $themeCollectionFactory; + } + + /** + * Return array of options as value-label pairs + * + * @return array Format: array('' => '', ...) + */ + public function toOptionArray() + { + // Load only visible themes that are used in frontend area + return $this->themeCollectionFactory->create()->loadRegisteredThemes()->toOptionHash(); + } +} diff --git a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Types.php b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Types.php index f3b90e45672f9..8dca86947bcf3 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Types.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Widget/Instance/Options/Types.php @@ -1,6 +1,6 @@ _escaper = $escaper; $this->_viewFileSystem = $viewFileSystem; @@ -155,6 +166,7 @@ public function __construct( $this->conditionsHelper = $conditionsHelper; $this->_directory = $filesystem->getDirectoryRead(DirectoryList::ROOT); $this->_namespaceResolver = $namespaceResolver; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); parent::__construct($context, $registry, $resource, $resourceCollection, $data); } @@ -250,7 +262,7 @@ public function beforeSave() \Magento\Framework\Math\Random::CHARS_LOWERS ); } - $this->setData('widget_parameters', serialize($parameters)); + $this->setData('widget_parameters', $this->serializer->serialize($parameters)); } $this->setData('page_groups', $tmpPageGroups); $this->setData('page_group_ids', $pageGroupIds); @@ -372,7 +384,7 @@ public function getStoreIds() public function getWidgetParameters() { if (is_string($this->getData('widget_parameters'))) { - return unserialize($this->getData('widget_parameters')); + return $this->serializer->unserialize($this->getData('widget_parameters')); } elseif (null === $this->getData('widget_parameters')) { return []; } diff --git a/app/code/Magento/Widget/Model/Widget/Instance/OptionsFactory.php b/app/code/Magento/Widget/Model/Widget/Instance/OptionsFactory.php index c1d4943f07e02..192008db98787 100644 --- a/app/code/Magento/Widget/Model/Widget/Instance/OptionsFactory.php +++ b/app/code/Magento/Widget/Model/Widget/Instance/OptionsFactory.php @@ -1,6 +1,6 @@ fieldDataConverterFactory = $fieldDataConverterFactory; + } + + /** + * {@inheritdoc} + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $setup->startSetup(); + + if (version_compare($context->getVersion(), '2.0.1', '<')) { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $fieldDataConverter->convert( + $setup->getConnection(), + $setup->getTable('widget_instance'), + 'instance_id', + 'widget_parameters' + ); + } + + $setup->endSetup(); + } +} diff --git a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Catalog/Category/ChooserTest.php b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Catalog/Category/ChooserTest.php index 281ff3f58d63a..baa4973eff549 100644 --- a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Catalog/Category/ChooserTest.php +++ b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Catalog/Category/ChooserTest.php @@ -1,6 +1,6 @@ disableOriginalConstructor() ->getMock(); - $this->escaperMock = $this->getMock(\Magento\Framework\Escaper::class, ['escapeHtml'], [], '', false); + $this->escaperMock = $this->getMock( + \Magento\Framework\Escaper::class, + ['escapeHtml', 'escapeHtmlAttr'], + [], + '', + false + ); + $this->escaperMock->expects($this->any())->method('escapeHtmlAttr')->willReturnArgument(0); $this->contextMock = $this->getMockBuilder(\Magento\Backend\Block\Context::class) ->setMethods(['getEventManager', 'getScopeConfig', 'getEscaper']) diff --git a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php index 737dbc905fabf..c23a8019e37ee 100644 --- a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php +++ b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Chooser/ContainerTest.php @@ -1,6 +1,6 @@ ' . ''; - $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true); - $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false); + $this->eventManagerMock->expects($this->exactly(2))->method('dispatch')->willReturn(true); $this->themeCollectionFactoryMock->expects($this->once()) ->method('create') @@ -153,8 +152,7 @@ public function testToHtmlCatalogCategoryLinkSimpleProduct() . '' . ''; - $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true); - $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false); + $this->eventManagerMock->expects($this->exactly(2))->method('dispatch')->willReturn(true); $this->themeCollectionFactoryMock->expects($this->once()) ->method('create') @@ -284,8 +282,7 @@ public function testToHtmlCmsStaticBlockAllProductTypes() . '' . ''; - $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true); - $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false); + $this->eventManagerMock->expects($this->exactly(2))->method('dispatch')->willReturn(true); $this->themeCollectionFactoryMock->expects($this->once()) ->method('create') @@ -402,8 +399,7 @@ public function testToHtmlOrderBySkuAllPages() . ''; - $this->eventManagerMock->expects($this->once())->method('dispatch')->willReturn(true); - $this->scopeConfigMock->expects($this->once())->method('getValue')->willReturn(false); + $this->eventManagerMock->expects($this->exactly(2))->method('dispatch')->willReturn(true); $this->themeCollectionFactoryMock->expects($this->once()) ->method('create') diff --git a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Tab/PropertiesTest.php b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Tab/PropertiesTest.php index 4dac50b538444..aafc1b3098273 100644 --- a/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Tab/PropertiesTest.php +++ b/app/code/Magento/Widget/Test/Unit/Block/Adminhtml/Widget/Instance/Edit/Tab/PropertiesTest.php @@ -1,6 +1,6 @@ conditions = $objectManagerHelper->getObject(\Magento\Widget\Helper\Conditions::class); + $this->serializer = $this->getMock(\Magento\Framework\Serialize\Serializer\Json::class, null); + $this->conditions = new \Magento\Widget\Helper\Conditions( + $this->serializer + ); } public function testEncodeDecode() diff --git a/app/code/Magento/Widget/Test/Unit/Model/Config/ConverterTest.php b/app/code/Magento/Widget/Test/Unit/Model/Config/ConverterTest.php index 4813dab78afd1..5bbb7ab425cf5 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/Config/ConverterTest.php +++ b/app/code/Magento/Widget/Test/Unit/Model/Config/ConverterTest.php @@ -1,6 +1,6 @@ themeCollectionMock = $this->getMock(ThemeCollection::class, [], [], '', false); + $this->themeCollectionFactoryMock = $this->getMock(ThemeCollectionFactory::class, ['create'], [], '', false); + $this->model = new Themes( + $this->themeCollectionFactoryMock + ); + } + + public function testToOptionArray() + { + $expectedResult = [ + 1 => 'Theme Label', + ]; + $this->themeCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->themeCollectionMock); + + $this->themeCollectionMock->expects($this->once())->method('loadRegisteredThemes')->willReturnSelf(); + $this->themeCollectionMock->expects($this->once())->method('toOptionHash')->willReturn($expectedResult); + + $this->assertEquals($expectedResult, $this->model->toOptionArray()); + } +} diff --git a/app/code/Magento/Widget/Test/Unit/Model/Template/FilterEmulateTest.php b/app/code/Magento/Widget/Test/Unit/Model/Template/FilterEmulateTest.php index 931c4b5599bff..85e38ed65e531 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/Template/FilterEmulateTest.php +++ b/app/code/Magento/Widget/Test/Unit/Model/Template/FilterEmulateTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Widget/Test/Unit/Model/_files/widget_config.php b/app/code/Magento/Widget/Test/Unit/Model/_files/widget_config.php index 96f675ae16746..df395183806e6 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/_files/widget_config.php +++ b/app/code/Magento/Widget/Test/Unit/Model/_files/widget_config.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Widget/etc/adminhtml/di.xml b/app/code/Magento/Widget/etc/adminhtml/di.xml index 6e7ee345f0ec9..ec53d6e86a083 100644 --- a/app/code/Magento/Widget/etc/adminhtml/di.xml +++ b/app/code/Magento/Widget/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/etc/adminhtml/menu.xml b/app/code/Magento/Widget/etc/adminhtml/menu.xml index 8806e57ba8479..22c4edb7171d4 100644 --- a/app/code/Magento/Widget/etc/adminhtml/menu.xml +++ b/app/code/Magento/Widget/etc/adminhtml/menu.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/etc/adminhtml/routes.xml b/app/code/Magento/Widget/etc/adminhtml/routes.xml index af005a9989bf6..2ee71d3c870ae 100644 --- a/app/code/Magento/Widget/etc/adminhtml/routes.xml +++ b/app/code/Magento/Widget/etc/adminhtml/routes.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/etc/di.xml b/app/code/Magento/Widget/etc/di.xml index 9a3a54202407a..1af987798b72d 100644 --- a/app/code/Magento/Widget/etc/di.xml +++ b/app/code/Magento/Widget/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/etc/module.xml b/app/code/Magento/Widget/etc/module.xml index afa9354041269..6dd2105dce794 100644 --- a/app/code/Magento/Widget/etc/module.xml +++ b/app/code/Magento/Widget/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Widget/etc/types.xsd b/app/code/Magento/Widget/etc/types.xsd index ad0b2f8e70205..fbf71754ed3af 100644 --- a/app/code/Magento/Widget/etc/types.xsd +++ b/app/code/Magento/Widget/etc/types.xsd @@ -1,7 +1,7 @@ @@ -100,4 +100,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Widget/etc/widget.xsd b/app/code/Magento/Widget/etc/widget.xsd index b22819245447b..374ff45303657 100644 --- a/app/code/Magento/Widget/etc/widget.xsd +++ b/app/code/Magento/Widget/etc/widget.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/etc/widget_file.xsd b/app/code/Magento/Widget/etc/widget_file.xsd index 920633e20a7a5..3c5abed4ec357 100644 --- a/app/code/Magento/Widget/etc/widget_file.xsd +++ b/app/code/Magento/Widget/etc/widget_file.xsd @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/registration.php b/app/code/Magento/Widget/registration.php index 25c8c6efbce65..57e469a907693 100644 --- a/app/code/Magento/Widget/registration.php +++ b/app/code/Magento/Widget/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml index 2d9cf935afa0d..1851dc49a68bc 100644 --- a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml +++ b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml @@ -1,7 +1,7 @@ @@ -52,7 +52,7 @@ Design Theme theme_id options - + 1 diff --git a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_edit.xml b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_edit.xml index 3be7e3752a731..1bb25aff15579 100644 --- a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_edit.xml +++ b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_edit.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_index.xml b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_index.xml index e04c115304764..6e0a1228fc28b 100644 --- a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_index.xml +++ b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_loadoptions.xml b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_loadoptions.xml index d9466860acf0d..51d4440c2f9f9 100644 --- a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_loadoptions.xml +++ b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_loadoptions.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml b/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml index 4e240770b0462..ed9b62bf925c9 100644 --- a/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml +++ b/app/code/Magento/Widget/view/adminhtml/templates/catalog/category/widget/tree.phtml @@ -1,6 +1,6 @@ '; + empty.text = 'escapeJs($block->escapeHtml(__('None'))); ?>'; empty.children = []; empty.id = 'none'; empty.path = '1/none'; diff --git a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml index 62d92ac38aecd..a2379d6af2911 100644 --- a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml +++ b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml @@ -1,6 +1,6 @@
    - + escapeHtml(__('Layout Updates')); ?>
    diff --git a/app/code/Magento/Widget/view/adminhtml/templates/instance/js.phtml b/app/code/Magento/Widget/view/adminhtml/templates/instance/js.phtml index 82a1652efa533..f5d5e9d08c7a9 100644 --- a/app/code/Magento/Widget/view/adminhtml/templates/instance/js.phtml +++ b/app/code/Magento/Widget/view/adminhtml/templates/instance/js.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Widget/view/frontend/layout/default.xml b/app/code/Magento/Widget/view/frontend/layout/default.xml index 7509438df2553..e01b48cc71b11 100644 --- a/app/code/Magento/Widget/view/frontend/layout/default.xml +++ b/app/code/Magento/Widget/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Widget/view/frontend/layout/print.xml b/app/code/Magento/Widget/view/frontend/layout/print.xml index 7509438df2553..e01b48cc71b11 100644 --- a/app/code/Magento/Widget/view/frontend/layout/print.xml +++ b/app/code/Magento/Widget/view/frontend/layout/print.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/Block/AbstractBlock.php b/app/code/Magento/Wishlist/Block/AbstractBlock.php index 91f7201a07e5a..e86d964e0c00d 100644 --- a/app/code/Magento/Wishlist/Block/AbstractBlock.php +++ b/app/code/Magento/Wishlist/Block/AbstractBlock.php @@ -1,6 +1,6 @@ getLayout()->getBlock('category.products.list'); if ($block) { $productCollection = $block->getLoadedProductCollection(); + $productTypes = []; /** @var $product \Magento\Catalog\Model\Product */ foreach ($productCollection as $product) { - $productTypes[] = $product->getTypeId(); + $productTypes[] = $this->escapeHtml($product->getTypeId()); } $this->productTypes = array_unique($productTypes); } diff --git a/app/code/Magento/Wishlist/Block/Adminhtml/Widget/Grid/Column/Filter/Text.php b/app/code/Magento/Wishlist/Block/Adminhtml/Widget/Grid/Column/Filter/Text.php index 218ef7018af3d..0578debc34fd1 100644 --- a/app/code/Magento/Wishlist/Block/Adminhtml/Widget/Grid/Column/Filter/Text.php +++ b/app/code/Magento/Wishlist/Block/Adminhtml/Widget/Grid/Column/Filter/Text.php @@ -1,6 +1,6 @@ $this->getProduct()->getTypeId()]; + return ['productType' => $this->escapeHtml($this->getProduct()->getTypeId())]; } /** diff --git a/app/code/Magento/Wishlist/Block/Customer/Sharing.php b/app/code/Magento/Wishlist/Block/Customer/Sharing.php index d447bd7014f22..9d27c1f2f1f76 100644 --- a/app/code/Magento/Wishlist/Block/Customer/Sharing.php +++ b/app/code/Magento/Wishlist/Block/Customer/Sharing.php @@ -1,6 +1,6 @@ $this->getProduct()->getTypeId()]; + return ['productType' => $this->escapeHtml($this->getProduct()->getTypeId())]; } /** diff --git a/app/code/Magento/Wishlist/Block/Link.php b/app/code/Magento/Wishlist/Block/Link.php index fea2ad5941c58..2381115f8c4f3 100644 --- a/app/code/Magento/Wishlist/Block/Link.php +++ b/app/code/Magento/Wishlist/Block/Link.php @@ -1,6 +1,6 @@ getData(self::SORT_ORDER); + } } diff --git a/app/code/Magento/Wishlist/Block/Rss/EmailLink.php b/app/code/Magento/Wishlist/Block/Rss/EmailLink.php index 75d29f5dd9d20..7963b43c1e81d 100644 --- a/app/code/Magento/Wishlist/Block/Rss/EmailLink.php +++ b/app/code/Magento/Wishlist/Block/Rss/EmailLink.php @@ -1,6 +1,6 @@ getRequest()->getParam('qty'); + $postQty = $this->getRequest()->getPostValue('qty'); + if ($postQty !== null && $qty !== $postQty) { + $qty = $postQty; + } if (is_array($qty)) { if (isset($qty[$itemId])) { $qty = $qty[$itemId]; diff --git a/app/code/Magento/Wishlist/Controller/Index/Configure.php b/app/code/Magento/Wishlist/Controller/Index/Configure.php index c3e29b9d6a9eb..253503f8fd793 100644 --- a/app/code/Magento/Wishlist/Controller/Index/Configure.php +++ b/app/code/Magento/Wishlist/Controller/Index/Configure.php @@ -1,6 +1,6 @@ is_string($item) ? $item : $item->getWishlistItemId()]; + $params = [ + 'item' => is_string($item) ? $item : $item->getWishlistItemId(), + ]; + if ($item instanceof \Magento\Wishlist\Model\Item) { + $params['qty'] = $item->getQty(); + } + return $params; } /** diff --git a/app/code/Magento/Wishlist/Helper/Rss.php b/app/code/Magento/Wishlist/Helper/Rss.php index 861d7514c4494..2cc48b3f93134 100644 --- a/app/code/Magento/Wishlist/Helper/Rss.php +++ b/app/code/Magento/Wishlist/Helper/Rss.php @@ -1,6 +1,6 @@ productTypeConfig = $productTypeConfig; $this->_storeManager = $storeManager; @@ -155,6 +164,8 @@ public function __construct( $this->_catalogUrl = $catalogUrl; $this->_wishlistOptFactory = $wishlistOptFactory; $this->_wishlOptionCollectionFactory = $wishlOptionCollectionFactory; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($context, $registry, $resource, $resourceCollection, $data); $this->productRepository = $productRepository; } @@ -472,7 +483,7 @@ public function getProductUrl() public function getBuyRequest() { $option = $this->getOptionByCode('info_buyRequest'); - $initialData = $option ? unserialize($option->getValue()) : null; + $initialData = $option ? $this->serializer->unserialize($option->getValue()) : null; if ($initialData instanceof \Magento\Framework\DataObject) { $initialData = $initialData->getData(); @@ -500,7 +511,7 @@ public function mergeBuyRequest($buyRequest) } $oldBuyRequest = $this->getBuyRequest()->getData(); - $sBuyRequest = serialize($buyRequest + $oldBuyRequest); + $sBuyRequest = $this->serializer->serialize($buyRequest + $oldBuyRequest); $option = $this->getOptionByCode('info_buyRequest'); if ($option) { @@ -523,7 +534,7 @@ public function setBuyRequest($buyRequest) { $buyRequest->setId($this->getId()); - $_buyRequest = serialize($buyRequest->getData()); + $_buyRequest = $this->serializer->serialize($buyRequest->getData()); $this->setData('buy_request', $_buyRequest); return $this; } diff --git a/app/code/Magento/Wishlist/Model/Item/Option.php b/app/code/Magento/Wishlist/Model/Item/Option.php index 6e81d86a94cc5..9c3800a125f51 100644 --- a/app/code/Magento/Wishlist/Model/Item/Option.php +++ b/app/code/Magento/Wishlist/Model/Item/Option.php @@ -1,6 +1,6 @@ setVisibility($this->_productVisibility->getVisibleInSiteIds()); } - $attributesToSelect = [ - 'name', - 'visibility', - 'small_image', - 'thumbnail', - 'links_purchased_separately', - 'links_title', - 'price_type' - ]; - $productCollection->addPriceData() ->addTaxPercents() ->addIdFilter($this->_productIds) - ->addAttributeToSelect($attributesToSelect) + ->addAttributeToSelect($this->_wishlistConfig->getProductAttributes()) ->addOptionsToResult() ->addUrlRewrite(); diff --git a/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection/Grid.php b/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection/Grid.php index e21dee5719516..43b8226444c0d 100644 --- a/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection/Grid.php +++ b/app/code/Magento/Wishlist/Model/ResourceModel/Item/Collection/Grid.php @@ -1,6 +1,6 @@ getProduct()->getCustomOption('simple_product'); - if ($customOption) { - /** @var \Magento\Framework\Pricing\PriceInfoInterface $priceInfo */ - $priceInfo = $customOption->getProduct()->getPriceInfo(); - $result = $priceInfo->getPrice(self::PRICE_CODE)->getValue(); - } - return max(0, $result); + $product = $customOption ? $customOption->getProduct() : $this->getProduct(); + $price = $product->getPriceInfo()->getPrice(self::PRICE_CODE)->getValue(); + + return max(0, $price); } /** diff --git a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/Downloadable.php b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/Downloadable.php index c2ce4d0aae836..51c7f10eec0d4 100644 --- a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/Downloadable.php +++ b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/Downloadable.php @@ -1,6 +1,6 @@ fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; + $this->queryGenerator = $queryGenerator; + } + + /** + * {@inheritdoc} + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + if (version_compare($context->getVersion(), '2.0.1', '<')) { + $this->upgradeToVersionTwoZeroOne($setup); + } + } + + /** + * Upgrade to version 2.0.1, convert data for `value` field in `wishlist_item_option table` + * from php-serialized to JSON format + * + * @param ModuleDataSetupInterface $setup + * @return void + */ + private function upgradeToVersionTwoZeroOne(ModuleDataSetupInterface $setup) + { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'code' => [ + 'parameters', + 'info_buyRequest', + 'bundle_option_ids', + 'bundle_selection_ids', + 'attributes', + 'bundle_selection_attributes', + ] + ] + ] + ); + $fieldDataConverter->convert( + $setup->getConnection(), + $setup->getTable('wishlist_item_option'), + 'option_id', + 'value', + $queryModifier + ); + $select = $setup->getConnection() + ->select() + ->from( + $setup->getTable('catalog_product_option'), + ['option_id'] + ) + ->where('type = ?', 'file'); + $iterator = $this->queryGenerator->generate('option_id', $select); + foreach ($iterator as $selectByRange) { + $codes = $setup->getConnection()->fetchCol($selectByRange); + $codes = array_map( + function ($id) { + return 'option_' . $id; + }, + $codes + ); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'code' => $codes + ] + ] + ); + $fieldDataConverter->convert( + $setup->getConnection(), + $setup->getTable('wishlist_item_option'), + 'option_id', + 'value', + $queryModifier + ); + } + } +} diff --git a/app/code/Magento/Wishlist/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Filter/TextTest.php b/app/code/Magento/Wishlist/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Filter/TextTest.php index 1917841355107..4b12b53f080f5 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Filter/TextTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Block/Adminhtml/Widget/Grid/Column/Filter/TextTest.php @@ -1,6 +1,6 @@ _mockWishlistData = $this->getMockBuilder( + $this->wishlistDataMock = $this->getMockBuilder( \Magento\Wishlist\Helper\Data::class )->disableOriginalConstructor()->getMock(); - $this->_mockContext = $this->getMockBuilder( + $this->contextMock = $this->getMockBuilder( \Magento\Framework\View\Element\Template\Context::class )->disableOriginalConstructor()->getMock(); - $this->_mockRegistry = $this->getMockBuilder(\Magento\Framework\Registry::class) + $this->registryMock = $this->getMockBuilder(\Magento\Framework\Registry::class) ->disableOriginalConstructor() ->getMock(); - - $this->_model = new \Magento\Wishlist\Block\Item\Configure( - $this->_mockContext, - $this->_mockWishlistData, - $this->_mockRegistry + $escaperMock = $this->getMockBuilder(\Magento\Framework\Escaper::class) + ->disableOriginalConstructor() + ->getMock(); + $escaperMock->method('escapeHtml') + ->willReturnCallback( + function ($string) { + return 'escapeHtml' . $string; + } + ); + $this->contextMock->expects($this->once()) + ->method('getEscaper') + ->willReturn($escaperMock); + + $this->model = new \Magento\Wishlist\Block\Item\Configure( + $this->contextMock, + $this->wishlistDataMock, + $this->registryMock ); } @@ -55,18 +67,18 @@ public function testGetWishlistOptions() \Magento\Catalog\Model\Product::class )->disableOriginalConstructor()->getMock(); $product->expects($this->once())->method('getTypeId')->willReturn($typeId); - $this->_mockRegistry->expects($this->once()) + $this->registryMock->expects($this->once()) ->method('registry') ->with($this->equalTo('product')) ->willReturn($product); - $this->assertEquals(['productType' => $typeId], $this->_model->getWishlistOptions()); + $this->assertEquals(['productType' => 'escapeHtml' . $typeId], $this->model->getWishlistOptions()); } public function testGetProduct() { $product = 'some test product'; - $this->_mockRegistry->expects( + $this->registryMock->expects( $this->once() )->method( 'registry' @@ -76,7 +88,7 @@ public function testGetProduct() $product ); - $this->assertEquals($product, $this->_model->getProduct()); + $this->assertEquals($product, $this->model->getProduct()); } public function testSetLayout() @@ -109,12 +121,12 @@ public function testSetLayout() false ); - $this->_mockRegistry->expects($this->exactly(2)) + $this->registryMock->expects($this->exactly(2)) ->method('registry') ->with('wishlist_item') ->willReturn($itemMock); - $this->_mockWishlistData->expects($this->once()) + $this->wishlistDataMock->expects($this->once()) ->method('getAddToCartUrl') ->with($itemMock) ->willReturn('some_url'); @@ -123,8 +135,8 @@ public function testSetLayout() ->method('setCustomAddToCartUrl') ->with('some_url'); - $this->assertEquals($this->_model, $this->_model->setLayout($layoutMock)); - $this->assertEquals($layoutMock, $this->_model->getLayout()); + $this->assertEquals($this->model, $this->model->setLayout($layoutMock)); + $this->assertEquals($layoutMock, $this->model->getLayout()); } public function testSetLayoutWithNoItem() @@ -149,19 +161,19 @@ public function testSetLayoutWithNoItem() ->with('product.info') ->willReturn($blockMock); - $this->_mockRegistry->expects($this->exactly(1)) + $this->registryMock->expects($this->exactly(1)) ->method('registry') ->with('wishlist_item') ->willReturn(null); - $this->_mockWishlistData->expects($this->never()) + $this->wishlistDataMock->expects($this->never()) ->method('getAddToCartUrl'); $blockMock->expects($this->never()) ->method('setCustomAddToCartUrl'); - $this->assertEquals($this->_model, $this->_model->setLayout($layoutMock)); - $this->assertEquals($layoutMock, $this->_model->getLayout()); + $this->assertEquals($this->model, $this->model->setLayout($layoutMock)); + $this->assertEquals($layoutMock, $this->model->getLayout()); } public function testSetLayoutWithNoBlockAndItem() @@ -179,13 +191,13 @@ public function testSetLayoutWithNoBlockAndItem() ->with('product.info') ->willReturn(null); - $this->_mockRegistry->expects($this->never()) + $this->registryMock->expects($this->never()) ->method('registry'); - $this->_mockWishlistData->expects($this->never()) + $this->wishlistDataMock->expects($this->never()) ->method('getAddToCartUrl'); - $this->assertEquals($this->_model, $this->_model->setLayout($layoutMock)); - $this->assertEquals($layoutMock, $this->_model->getLayout()); + $this->assertEquals($this->model, $this->model->setLayout($layoutMock)); + $this->assertEquals($layoutMock, $this->model->getLayout()); } } diff --git a/app/code/Magento/Wishlist/Test/Unit/Block/Rss/EmailLinkTest.php b/app/code/Magento/Wishlist/Test/Unit/Block/Rss/EmailLinkTest.php index d5191140ac8c9..05055a2ae0755 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Block/Rss/EmailLinkTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Block/Rss/EmailLinkTest.php @@ -1,6 +1,6 @@ requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) ->disableOriginalConstructor() - ->setMethods(['getParams', 'getParam', 'isAjax']) + ->setMethods(['getParams', 'getParam', 'isAjax', 'getPostValue']) ->getMockForAbstractClass(); $this->redirectMock = $this->getMockBuilder(\Magento\Framework\App\Response\RedirectInterface::class) @@ -916,4 +916,176 @@ public function testExecuteWithoutQuantityArrayAndConfigurable() $this->assertSame($this->resultRedirectMock, $this->model->execute()); } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testExecuteWithEditQuantity() + { + $itemId = 2; + $wishlistId = 1; + $qty = 1; + $postQty = 2; + $productId = 4; + $indexUrl = 'index_url'; + $configureUrl = 'configure_url'; + $options = [5 => 'option']; + $params = ['item' => $itemId, 'qty' => $qty]; + + $this->formKeyValidator->expects($this->once()) + ->method('validate') + ->with($this->requestMock) + ->willReturn(true); + + $itemMock = $this->getMockBuilder(\Magento\Wishlist\Model\Item::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'load', + 'getId', + 'getWishlistId', + 'setQty', + 'setOptions', + 'getBuyRequest', + 'mergeBuyRequest', + 'addToCart', + 'getProduct', + 'getProductId', + ] + ) + ->getMock(); + + $this->requestMock->expects($this->at(0)) + ->method('getParam') + ->with('item', null) + ->willReturn($itemId); + $this->itemFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($itemMock); + + $itemMock->expects($this->once()) + ->method('load') + ->with($itemId, null) + ->willReturnSelf(); + $itemMock->expects($this->exactly(2)) + ->method('getId') + ->willReturn($itemId); + $itemMock->expects($this->once()) + ->method('getWishlistId') + ->willReturn($wishlistId); + + $wishlistMock = $this->getMockBuilder(\Magento\Wishlist\Model\Wishlist::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->wishlistProviderMock->expects($this->once()) + ->method('getWishlist') + ->with($wishlistId) + ->willReturn($wishlistMock); + + $this->requestMock->expects($this->at(1)) + ->method('getParam') + ->with('qty', null) + ->willReturn($qty); + + $this->requestMock->expects($this->once()) + ->method('getPostValue') + ->with('qty') + ->willReturn($postQty); + + $this->quantityProcessorMock->expects($this->once()) + ->method('process') + ->with($postQty) + ->willReturnArgument(0); + + $itemMock->expects($this->once()) + ->method('setQty') + ->with($postQty) + ->willReturnSelf(); + + $this->urlMock->expects($this->at(0)) + ->method('getUrl') + ->with('*/*', null) + ->willReturn($indexUrl); + + $itemMock->expects($this->once()) + ->method('getProductId') + ->willReturn($productId); + + $this->urlMock->expects($this->at(1)) + ->method('getUrl') + ->with('*/*/configure/', ['id' => $itemId, 'product_id' => $productId]) + ->willReturn($configureUrl); + + $optionMock = $this->getMockBuilder(\Magento\Wishlist\Model\Item\Option::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->optionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($optionMock); + + $optionsMock = $this->getMockBuilder(\Magento\Wishlist\Model\ResourceModel\Item\Option\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $optionMock->expects($this->once()) + ->method('getCollection') + ->willReturn($optionsMock); + + $optionsMock->expects($this->once()) + ->method('addItemFilter') + ->with([$itemId]) + ->willReturnSelf(); + $optionsMock->expects($this->once()) + ->method('getOptionsByItem') + ->with($itemId) + ->willReturn($options); + + $itemMock->expects($this->once()) + ->method('setOptions') + ->with($options) + ->willReturnSelf(); + + $this->requestMock->expects($this->once()) + ->method('getParams') + ->willReturn($params); + + $buyRequestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) + ->disableOriginalConstructor() + ->getMock(); + + $itemMock->expects($this->once()) + ->method('getBuyRequest') + ->willReturn($buyRequestMock); + + $this->productHelperMock->expects($this->once()) + ->method('addParamsToBuyRequest') + ->with($params, ['current_config' => $buyRequestMock]) + ->willReturn($buyRequestMock); + + $itemMock->expects($this->once()) + ->method('mergeBuyRequest') + ->with($buyRequestMock) + ->willReturnSelf(); + $itemMock->expects($this->once()) + ->method('addToCart') + ->with($this->checkoutCartMock, true) + ->willThrowException(new \Magento\Framework\Exception\LocalizedException(__('message'))); + + $this->messageManagerMock->expects($this->once()) + ->method('addNotice') + ->with('message', null) + ->willReturnSelf(); + + $this->helperMock->expects($this->once()) + ->method('calculate') + ->willReturnSelf(); + + $this->resultRedirectMock->expects($this->once()) + ->method('setUrl') + ->with($configureUrl) + ->willReturnSelf(); + + $this->assertSame($this->resultRedirectMock, $this->model->execute()); + } } diff --git a/app/code/Magento/Wishlist/Test/Unit/Controller/Index/FromcartTest.php b/app/code/Magento/Wishlist/Test/Unit/Controller/Index/FromcartTest.php index d894cc8d9e6d1..5f01f55927cec 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Controller/Index/FromcartTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Controller/Index/FromcartTest.php @@ -1,6 +1,6 @@ setMethods([ 'getProduct', 'getWishlistItemId', + 'getQty', ]) ->getMock(); @@ -217,6 +218,7 @@ public function testGetAddToCartParams() $url = 'result url'; $storeId = 1; $wishlistItemId = 1; + $wishlistItemQty = 1; $this->wishlistItem->expects($this->once()) ->method('getProduct') @@ -224,6 +226,9 @@ public function testGetAddToCartParams() $this->wishlistItem->expects($this->once()) ->method('getWishlistItemId') ->willReturn($wishlistItemId); + $this->wishlistItem->expects($this->once()) + ->method('getQty') + ->willReturn($wishlistItemQty); $this->product->expects($this->once()) ->method('isVisibleInSiteVisibility') @@ -243,9 +248,13 @@ public function testGetAddToCartParams() ->with('wishlist/index/cart') ->willReturn($url); + $expected = [ + 'item' => $wishlistItemId, + 'qty' => $wishlistItemQty, + ]; $this->postDataHelper->expects($this->once()) ->method('getPostData') - ->with($url, ['item' => $wishlistItemId]) + ->with($url, $expected) ->willReturn($url); $this->assertEquals($url, $this->model->getAddToCartParams($this->wishlistItem)); @@ -256,6 +265,7 @@ public function testGetAddToCartParamsWithReferer() $url = 'result url'; $storeId = 1; $wishlistItemId = 1; + $wishlistItemQty = 1; $referer = 'referer'; $refererEncoded = 'referer_encoded'; @@ -265,6 +275,9 @@ public function testGetAddToCartParamsWithReferer() $this->wishlistItem->expects($this->once()) ->method('getWishlistItemId') ->willReturn($wishlistItemId); + $this->wishlistItem->expects($this->once()) + ->method('getQty') + ->willReturn($wishlistItemQty); $this->product->expects($this->once()) ->method('isVisibleInSiteVisibility') @@ -288,9 +301,14 @@ public function testGetAddToCartParamsWithReferer() ->with('wishlist/index/cart') ->willReturn($url); + $expected = [ + 'item' => $wishlistItemId, + ActionInterface::PARAM_NAME_URL_ENCODED => $refererEncoded, + 'qty' => $wishlistItemQty, + ]; $this->postDataHelper->expects($this->once()) ->method('getPostData') - ->with($url, ['item' => $wishlistItemId, ActionInterface::PARAM_NAME_URL_ENCODED => $refererEncoded]) + ->with($url, $expected) ->willReturn($url); $this->assertEquals($url, $this->model->getAddToCartParams($this->wishlistItem, true)); @@ -363,6 +381,7 @@ public function testGetSharedAddToCartUrl() $url = 'result url'; $storeId = 1; $wishlistItemId = 1; + $wishlistItemQty = 1; $this->wishlistItem->expects($this->once()) ->method('getProduct') @@ -370,6 +389,9 @@ public function testGetSharedAddToCartUrl() $this->wishlistItem->expects($this->once()) ->method('getWishlistItemId') ->willReturn($wishlistItemId); + $this->wishlistItem->expects($this->once()) + ->method('getQty') + ->willReturn($wishlistItemQty); $this->product->expects($this->once()) ->method('isVisibleInSiteVisibility') @@ -383,9 +405,13 @@ public function testGetSharedAddToCartUrl() ->with('wishlist/shared/cart') ->willReturn($url); + $exptected = [ + 'item' => $wishlistItemId, + 'qty' => $wishlistItemQty, + ]; $this->postDataHelper->expects($this->once()) ->method('getPostData') - ->with($url, ['item' => $wishlistItemId]) + ->with($url, $exptected) ->willReturn($url); $this->assertEquals($url, $this->model->getSharedAddToCartUrl($this->wishlistItem)); diff --git a/app/code/Magento/Wishlist/Test/Unit/Helper/RssTest.php b/app/code/Magento/Wishlist/Test/Unit/Helper/RssTest.php index d768e947ac70b..d2d1586fa0bf3 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Helper/RssTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Helper/RssTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Customer\Api\Data\CustomerInterface::class, [], [], '', false); $wishlistSharingUrl = 'wishlist/shared/index/1'; - $locale = 'en_US'; $productUrl = 'http://product.url/'; $productName = 'Product name'; @@ -160,25 +159,6 @@ public function testGetRssData() $this->urlBuilderMock->expects($this->once()) ->method('getUrl') ->will($this->returnValue($wishlistSharingUrl)); - $this->scopeConfig->expects($this->any()) - ->method('getValue') - ->will($this->returnValueMap( - [ - [ - 'advanced/modules_disable_output/Magento_Rss', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, - null, - null, - ], - [ - Data::XML_PATH_DEFAULT_LOCALE, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, - null, - $locale - ], - ] - ) - ); $staticArgs = [ 'productName' => $productName, diff --git a/app/code/Magento/Wishlist/Test/Unit/Model/WishlistTest.php b/app/code/Magento/Wishlist/Test/Unit/Model/WishlistTest.php index 614a9b244a820..be7d42fd03ac6 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Model/WishlistTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Model/WishlistTest.php @@ -1,6 +1,6 @@ getMockForAbstractClass(); - $this->saleableItem->expects($this->once()) - ->method('getPriceInfo') - ->willReturn($this->priceInfoMock); $this->calculator = $this->getMockBuilder(\Magento\Framework\Pricing\Adjustment\CalculatorInterface::class) ->getMockForAbstractClass(); @@ -59,7 +50,7 @@ protected function setUp() $this->priceCurrency = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class) ->getMockForAbstractClass(); - $this->model = new ConfigurableProduct( + $this->model = new \Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct( $this->saleableItem, null, $this->calculator, @@ -82,7 +73,7 @@ public function testGetValue() ->getMock(); $this->priceInfoMock->expects($this->once()) ->method('getPrice') - ->with(ConfigurableProduct::PRICE_CODE) + ->with(\Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct::PRICE_CODE) ->willReturn($priceMock); $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) @@ -109,11 +100,28 @@ public function testGetValue() public function testGetValueWithNoCustomOption() { + $priceValue = 100; + + $priceMock = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class) + ->getMockForAbstractClass(); + $priceMock->expects($this->once()) + ->method('getValue') + ->willReturn($priceValue); + $this->saleableItem->expects($this->once()) ->method('getCustomOption') ->with('simple_product') ->willReturn(null); - $this->assertEquals(0, $this->model->getValue()); + $this->saleableItem->expects($this->once()) + ->method('getPriceInfo') + ->willReturn($this->priceInfoMock); + + $this->priceInfoMock->expects($this->once()) + ->method('getPrice') + ->with(\Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct::PRICE_CODE) + ->willReturn($priceMock); + + $this->assertEquals(100, $this->model->getValue()); } } diff --git a/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/DownloadableTest.php b/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/DownloadableTest.php index 5c8bd7c09cc61..850e480cddabf 100644 --- a/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/DownloadableTest.php +++ b/app/code/Magento/Wishlist/Test/Unit/Pricing/ConfiguredPrice/DownloadableTest.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Wishlist/etc/adminhtml/di.xml b/app/code/Magento/Wishlist/etc/adminhtml/di.xml index 78e9a8cb5e3cd..285f157c1c080 100644 --- a/app/code/Magento/Wishlist/etc/adminhtml/di.xml +++ b/app/code/Magento/Wishlist/etc/adminhtml/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/adminhtml/system.xml b/app/code/Magento/Wishlist/etc/adminhtml/system.xml index 8e77914c54b63..13be521dd7923 100644 --- a/app/code/Magento/Wishlist/etc/adminhtml/system.xml +++ b/app/code/Magento/Wishlist/etc/adminhtml/system.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/catalog_attributes.xml b/app/code/Magento/Wishlist/etc/catalog_attributes.xml index 6dfda390e4401..448434a6cbda5 100644 --- a/app/code/Magento/Wishlist/etc/catalog_attributes.xml +++ b/app/code/Magento/Wishlist/etc/catalog_attributes.xml @@ -1,12 +1,18 @@ + + + + + + diff --git a/app/code/Magento/Wishlist/etc/config.xml b/app/code/Magento/Wishlist/etc/config.xml index d02d26defbaa6..4ffc468af7ec4 100644 --- a/app/code/Magento/Wishlist/etc/config.xml +++ b/app/code/Magento/Wishlist/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/di.xml b/app/code/Magento/Wishlist/etc/di.xml index a102672216bc8..9bde30017bff4 100644 --- a/app/code/Magento/Wishlist/etc/di.xml +++ b/app/code/Magento/Wishlist/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/email_templates.xml b/app/code/Magento/Wishlist/etc/email_templates.xml index 5a60d73cbae37..30abb74f7e558 100644 --- a/app/code/Magento/Wishlist/etc/email_templates.xml +++ b/app/code/Magento/Wishlist/etc/email_templates.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/events.xml b/app/code/Magento/Wishlist/etc/events.xml index cea2cf6527ed6..108ca432fdd80 100644 --- a/app/code/Magento/Wishlist/etc/events.xml +++ b/app/code/Magento/Wishlist/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/frontend/di.xml b/app/code/Magento/Wishlist/etc/frontend/di.xml index f6510ee387fc7..d44556d90add0 100644 --- a/app/code/Magento/Wishlist/etc/frontend/di.xml +++ b/app/code/Magento/Wishlist/etc/frontend/di.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/frontend/events.xml b/app/code/Magento/Wishlist/etc/frontend/events.xml index 948579a633b5a..f7878fdfb44d5 100644 --- a/app/code/Magento/Wishlist/etc/frontend/events.xml +++ b/app/code/Magento/Wishlist/etc/frontend/events.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/frontend/page_types.xml b/app/code/Magento/Wishlist/etc/frontend/page_types.xml index a9824a8a790d9..20efa156e4b2c 100644 --- a/app/code/Magento/Wishlist/etc/frontend/page_types.xml +++ b/app/code/Magento/Wishlist/etc/frontend/page_types.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/frontend/routes.xml b/app/code/Magento/Wishlist/etc/frontend/routes.xml index 2435ac33ec787..c4c349c3859d6 100644 --- a/app/code/Magento/Wishlist/etc/frontend/routes.xml +++ b/app/code/Magento/Wishlist/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/Wishlist/etc/frontend/sections.xml b/app/code/Magento/Wishlist/etc/frontend/sections.xml index bf6b55d1448f3..d9e0faf2d63d2 100644 --- a/app/code/Magento/Wishlist/etc/frontend/sections.xml +++ b/app/code/Magento/Wishlist/etc/frontend/sections.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/etc/module.xml b/app/code/Magento/Wishlist/etc/module.xml index a8b0fa21edee3..1f59057640ce9 100644 --- a/app/code/Magento/Wishlist/etc/module.xml +++ b/app/code/Magento/Wishlist/etc/module.xml @@ -1,12 +1,12 @@ - + diff --git a/app/code/Magento/Wishlist/etc/view.xml b/app/code/Magento/Wishlist/etc/view.xml index 9f8ab1326b1f4..df6005a236540 100644 --- a/app/code/Magento/Wishlist/etc/view.xml +++ b/app/code/Magento/Wishlist/etc/view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/registration.php b/app/code/Magento/Wishlist/registration.php index b44f3c4435666..07a81f402add4 100644 --- a/app/code/Magento/Wishlist/registration.php +++ b/app/code/Magento/Wishlist/registration.php @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml b/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml index 9b1f9f5d2e831..ca75cbc2f6869 100644 --- a/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml +++ b/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/adminhtml/templates/customer/edit/tab/wishlist.phtml b/app/code/Magento/Wishlist/view/adminhtml/templates/customer/edit/tab/wishlist.phtml index 63377fcbbbea4..527377b69a131 100644 --- a/app/code/Magento/Wishlist/view/adminhtml/templates/customer/edit/tab/wishlist.phtml +++ b/app/code/Magento/Wishlist/view/adminhtml/templates/customer/edit/tab/wishlist.phtml @@ -1,6 +1,6 @@ escapeJs($block->getJsObjectName()) ?>.url + '?ajax=true' + urlParams; + var url = escapeJs($block->escapeUrl($block->getJsObjectName())) ?>.url + '?ajax=true' + urlParams; new Ajax.Updater( - escapeJs($block->getJsObjectName()) ?>.containerId, + escapeJs($block->escapeHtml($block->getJsObjectName())) ?>.containerId, url, { parameters: {form_key: FORM_KEY}, - onComplete: escapeJs($block->getJsObjectName()) ?>.initGrid.bind(escapeJs($block->getJsObjectName()) ?>), + onComplete: escapeJs($block->escapeHtml($block->getJsObjectName())) ?>.initGrid.bind(escapeJs($block->escapeHtml($block->getJsObjectName())) ?>), evalScripts:true } ); @@ -50,7 +50,7 @@ var self = this; confirm({ - content: '', + content: 'escapeJs($block->escapeHtml(__('Are you sure you want to remove this item?'))) ?>', actions: { confirm: function () { self.reload('&delete=' + itemId); @@ -63,8 +63,8 @@ productConfigure.addListType( 'wishlist', { - urlFetch: 'escapeUrl($block->getUrl('customer/wishlist_product_composite_wishlist/configure')) ?>', - urlConfirm: 'escapeUrl($block->getUrl('customer/wishlist_product_composite_wishlist/update')) ?>' + urlFetch: 'escapeJs($block->escapeUrl($block->getUrl('customer/wishlist_product_composite_wishlist/configure'))) ?>', + urlConfirm: 'escapeJs($block->escapeUrl($block->getUrl('customer/wishlist_product_composite_wishlist/update'))) ?>' } ); //--> diff --git a/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml b/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml index 780d137b58f1f..300fa819d2ad6 100644 --- a/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml +++ b/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/email/share_notification.html b/app/code/Magento/Wishlist/view/frontend/email/share_notification.html index d2cd27af00422..ee87933768f19 100644 --- a/app/code/Magento/Wishlist/view/frontend/email/share_notification.html +++ b/app/code/Magento/Wishlist/view/frontend/email/share_notification.html @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml b/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml index dd9fb74924115..d3401839bf963 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml index 4c01d341bb682..7c09f10b29a90 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/catalog_product_view.xml @@ -1,7 +1,7 @@ @@ -16,7 +16,7 @@ - diff --git a/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_advanced_result.xml b/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_advanced_result.xml index 711165800ccd5..3aa9beb2fd957 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_advanced_result.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_advanced_result.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_result_index.xml b/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_result_index.xml index 711165800ccd5..3aa9beb2fd957 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_result_index.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/catalogsearch_result_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_index.xml b/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_index.xml index ad5c10981f107..df2fb0c3485af 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_index.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_item_renderers.xml index 846403b72c359..d4cf08d706a59 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/checkout_cart_item_renderers.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml b/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml index c1dc653efbe7e..cd87b9c6cb6a1 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/customer_account.xml @@ -1,17 +1,18 @@ - + wishlist My Wish List + 210 diff --git a/app/code/Magento/Wishlist/view/frontend/layout/default.xml b/app/code/Magento/Wishlist/view/frontend/layout/default.xml index a0fc577547c5a..4fd69462ed9cc 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/default.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/default.xml @@ -1,7 +1,7 @@ @@ -11,7 +11,11 @@ - + + + 60 + + diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_items.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_items.xml index a14f175beed1b..63120efab9dd1 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_items.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_items.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_rss.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_rss.xml index 1a5007b5c5590..7a42e2cb6cf12 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_rss.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_email_rss.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml index 50ba68940fc9d..fb5c00255c136 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure.xml @@ -1,7 +1,7 @@ @@ -9,7 +9,7 @@ - diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml index dbb680f8f2580..98a41c7a0533c 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_bundle.xml @@ -1,7 +1,7 @@ @@ -20,9 +20,9 @@ - - diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_configurable.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_configurable.xml index 93ddf5c6ae546..118086e9d4068 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_configurable.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_configurable.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_downloadable.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_downloadable.xml index c2f2ca116a7cd..be5246ce56b78 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_downloadable.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_downloadable.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_grouped.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_grouped.xml index 7a2374ea56f73..85ba977673765 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_grouped.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_grouped.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_simple.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_simple.xml index 7509438df2553..e01b48cc71b11 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_simple.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_configure_type_simple.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_index.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_index.xml index 4ca84bc898ccd..eb02bbf5849e7 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_index.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_share.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_share.xml index eb8ce46d44953..4b470dd2ae08d 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_share.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_index_share.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml index 0c6e11ae6183b..cfda992ced092 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/wishlist_shared_index.xml @@ -1,7 +1,7 @@ diff --git a/app/code/Magento/Wishlist/view/frontend/requirejs-config.js b/app/code/Magento/Wishlist/view/frontend/requirejs-config.js index f46ad639ab41c..e078023ac56ea 100644 --- a/app/code/Magento/Wishlist/view/frontend/requirejs-config.js +++ b/app/code/Magento/Wishlist/view/frontend/requirejs-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -11,4 +11,4 @@ var config = { wishlistSearch: 'Magento_Wishlist/js/search' } } -}; \ No newline at end of file +}; diff --git a/app/code/Magento/Wishlist/view/frontend/templates/addto.phtml b/app/code/Magento/Wishlist/view/frontend/templates/addto.phtml index 99c505fdc0ca3..ad05e00487a4d 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/addto.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/addto.phtml @@ -1,8 +1,10 @@ \ No newline at end of file + diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/configure/addto/wishlist.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/configure/addto/wishlist.phtml index 9d721e9a50cfd..16bd68c11858a 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/item/configure/addto/wishlist.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/item/configure/addto/wishlist.phtml @@ -1,6 +1,6 @@ helper('Magento\Wishlist\Helper\Data')->isAllow()) : ?> - + escapeHtml(__('Update Wish List')) ?> \ No newline at end of file + diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/list.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/list.phtml index 9850f8fa7ea21..dce3241ea5f92 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/item/list.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/item/list.phtml @@ -1,6 +1,6 @@ getColumns();
    - + escapeHtml(__('This Wish List has no Items'));?>
    diff --git a/app/code/Magento/Wishlist/view/frontend/templates/js/components.phtml b/app/code/Magento/Wishlist/view/frontend/templates/js/components.phtml index e490a6aa04923..bdcb2e9bf7747 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/js/components.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/js/components.phtml @@ -1,6 +1,6 @@ -escapeHtml($block->getData('product_name'))) ?> here to continue shopping.', $block->escapeUrl($block->getData('referer'))); +escapeHtml(__('%1 has been added to your Wish List.', $block->getData('product_name'))) ?> escapeHtml(__('Click here to continue shopping.', $block->getData('referer')), ['a']); diff --git a/app/code/Magento/Wishlist/view/frontend/templates/options_list.phtml b/app/code/Magento/Wishlist/view/frontend/templates/options_list.phtml index 8f1b5b3898d22..136e33c95cf0e 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/options_list.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/options_list.phtml @@ -1,6 +1,6 @@ getOptionList(); ?>
    - + escapeHtml(__('See Details')) ?>
    - + escapeHtml(__('Options Details')); ?>
    escapeHtml($option['label']) ?>
    diff --git a/app/code/Magento/Wishlist/view/frontend/templates/rss/email.phtml b/app/code/Magento/Wishlist/view/frontend/templates/rss/email.phtml index 13685949a2971..01a0cc69ef83b 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/rss/email.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/rss/email.phtml @@ -1,6 +1,6 @@ getLink()): ?>

    - escapeHtml($this->helper('Magento\Wishlist\Helper\Data')->getCustomerName())) ?> + escapeHtml(__("RSS link to %1's wishlist", $this->helper('Magento\Wishlist\Helper\Data')->getCustomerName())) ?>
    escapeUrl($block->getLink()); ?>

    diff --git a/app/code/Magento/Wishlist/view/frontend/templates/rss/wishlist.phtml b/app/code/Magento/Wishlist/view/frontend/templates/rss/wishlist.phtml index 1e297c4673d70..091a4cec8810b 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/rss/wishlist.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/rss/wishlist.phtml @@ -1,6 +1,6 @@ isRssAllowed() && $block->getLink() && $this->helper('Magento\Wishlist\Helper\Data')->getWishlist()->getItemsCount()): ?> - + escapeHtml(__('RSS Feed')) ?> diff --git a/app/code/Magento/Wishlist/view/frontend/templates/shared.phtml b/app/code/Magento/Wishlist/view/frontend/templates/shared.phtml index 201a5ef372210..cb0f35fd88131 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/shared.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/shared.phtml @@ -1,6 +1,6 @@ escapeUrl($block->getUrl('wishlist/index/update')) ?>" method="post">
    escapeHtml(__('Feed')); ?>
    escapeHtml(__('Miscellaneous Feeds')) ?>
    escapeHtml($feed['label']) ?> - + escapeHtml(__('Get Feed')); ?>
    escapeHtml($item['label']) ?> - + escapeHtml(__('Get Feed')); ?>
    - + - - - + + + @@ -28,7 +28,7 @@ $isVisibleProduct = $product->isVisibleInSiteVisibility(); ?> - - - + @@ -73,20 +73,20 @@ isSaleable()):?>
    -
    +
    escapeHtml(__('Wish List is empty now.')) ?>
    diff --git a/app/code/Magento/Wishlist/view/frontend/templates/sharing.phtml b/app/code/Magento/Wishlist/view/frontend/templates/sharing.phtml index a21811b384f5b..7c68634ee8601 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/sharing.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/sharing.phtml @@ -1,6 +1,6 @@ escapeUrl($block->getSendUrl()) ?>" id="form-validate" method="post" - data-hasrequired="" + data-hasrequired="escapeHtmlAttr(__('* Required Fields')) ?>" data-mage-init='{"validation":{}}'>
    getBlockHtml('formkey')?> -
    + escapeHtml(__('Sharing Information')) ?>
    - +
    - +
    helper('Magento\Wishlist\Helper\Rss')->isRssAllow()): ?>
    - +
    @@ -42,12 +42,12 @@
    -
    diff --git a/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml b/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml index 28e339162d5de..d9518eaa8f465 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/sidebar.phtml @@ -1,6 +1,6 @@ helper('Magento\Wishlist\Helper\Data');
    - + escapeHtml(__('Last Added Items')) ?>
    1. @@ -39,18 +39,18 @@ $wishlistHelper = $this->helper('Magento\Wishlist\Helper\Data');
      - + escapeHtml(__('Add to Cart')) ?> - +
    @@ -62,12 +62,12 @@ $wishlistHelper = $this->helper('Magento\Wishlist\Helper\Data');
    + title="escapeHtmlAttr(__('Go to Wish List')) ?>">escapeHtml(__('Go to Wish List')) ?>
    -
    +
    escapeHtml(__('You have no items in your wish list.')) ?>
    diff --git a/app/code/Magento/Wishlist/view/frontend/templates/view.phtml b/app/code/Magento/Wishlist/view/frontend/templates/view.phtml index 748e1e4386cb8..af6d2f2c01a8b 100644 --- a/app/code/Magento/Wishlist/view/frontend/templates/view.phtml +++ b/app/code/Magento/Wishlist/view/frontend/templates/view.phtml @@ -1,6 +1,6 @@ getChildBlock('items')->setItems($block->getWishlistItems()); ?> getChildHtml('items');?> -
    +
    escapeHtml(__('You have no items in your wish list.')) ?>
    getChildHtml('bottom'); ?>
    @@ -32,7 +32,7 @@
    diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js index d442c7e878a24..802a8af783ed8 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/js/add-to-wishlist.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/search.js b/app/code/Magento/Wishlist/view/frontend/web/js/search.js index 909ba16b63055..b6e8491d9c35f 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/js/search.js +++ b/app/code/Magento/Wishlist/view/frontend/web/js/search.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true jquery:true*/ @@ -39,4 +39,4 @@ define([ }); return $.mage.wishlistSearch; -}); \ No newline at end of file +}); diff --git a/app/code/Magento/Wishlist/view/frontend/web/js/view/wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/js/view/wishlist.js index 64479db505ffb..a569415129eab 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/js/view/wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/js/view/wishlist.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/code/Magento/Wishlist/view/frontend/web/wishlist.js b/app/code/Magento/Wishlist/view/frontend/web/wishlist.js index a4fdc178c704f..25b32d0310577 100644 --- a/app/code/Magento/Wishlist/view/frontend/web/wishlist.js +++ b/app/code/Magento/Wishlist/view/frontend/web/wishlist.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint browser:true sub:true*/ @@ -47,6 +47,7 @@ define([ event.preventDefault(); $.mage.dataPost().postData($(event.currentTarget).data('post-remove')); }, this)) + .on('click', this.options.addToCartSelector, $.proxy(this._beforeAddToCart, this)) .on('click', this.options.addAllToCartSelector, $.proxy(this._addAllWItemsToCart, this)) .on('focusin focusout', this.options.commentInputType, $.proxy(this._focusComment, this)); } @@ -59,6 +60,27 @@ define([ }); }, + /** + * Process data before add to cart + * + * - update item's qty value. + * + * @param {Event} event + * @private + */ + _beforeAddToCart: function(event) { + var elem = $(event.currentTarget), + itemId = elem.data(this.options.dataAttribute), + qtyName = $.validator.format(this.options.nameFormat, itemId), + qtyValue = elem.parents().find('[name="' + qtyName + '"]').val(), + params = elem.data('post'); + + if (params) { + params.data = $.extend({}, params.data, {'qty': qtyValue}); + elem.data('post', params); + } + }, + /** * Add wish list items to cart. * @private diff --git a/app/design/adminhtml/Magento/backend/Magento_AdminNotification/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_AdminNotification/web/css/source/_module.less index 585269e14d685..2aec6b9155561 100644 --- a/app/design/adminhtml/Magento/backend/Magento_AdminNotification/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_AdminNotification/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -8,7 +8,16 @@ // _____________________________________________ @message-system__background-color: @color-lazy-sun; -@message-system-short-message__padding-vertical: 1.8rem; +@message-system__border-color: @color-gray82; +@message-system__border-width: .1rem; +@message-system__color: @color-gray20; +@message-system-short__padding-vertical: 1.5rem; +@message-system-short-wrapper__height: 5rem; + +// Triangle marker +@message-system-triangle__height: .5rem; +@message-system-triangle__padding-right: 3rem; +@message-system-triangle__width: .8rem; // // Message system @@ -17,34 +26,124 @@ .message-system-inner { &:extend(.abs-clearfix all); background: @message-system__background-color; + border: solid @message-system__border-color; + border-width: 0 @message-system__border-width @message-system__border-width; + position: relative; + + .message-error { + background: none; + } + + .message { + background: none; + margin: 0 0 -3px; + overflow: hidden; + padding: @message-system-short__padding-vertical 0 @message-system-short__padding-vertical 3.3rem; + + &:before { + left: .3rem; + } + } - .message-system-list { - float: left; - width: 75%; + .action-menu-item { + &.action-close-wrapper { + width: 3.5rem; + } + + .action-close { + float: right; + } + + float: right; + padding: @message-system-short__padding-vertical 0 0; + vertical-align: top; } } .message-system-list { + border-bottom: 1px solid @message-system__border-color; + border-top: 1px solid @message-system__border-color; list-style: none; - margin: 0; - padding: 0; + margin: 0 0 1.5rem; + + li { + + li { + border-top: 1px dashed @message-system__border-color; + } + } } .message-system-short { + min-height: @message-system-short-wrapper__height; + + .action-close-wrapper { + display: none; + } +} + +.message-system-short-wrapper { overflow: hidden; - text-align: right; + padding: 0 1.5rem 0 @indent__l; +} - .message-system-short-label { - display: inline-block; - padding: @message-system-short-message__padding-vertical .3rem @message-system-short-message__padding-vertical 1rem; +.message-system-collapsible { + background: @message-system__background-color; + border: @message-system__border-width solid @message-system__border-color; + border-top: 0; + display: none; + left: -1px; + padding: 0 @indent__l @message-system-short__padding-vertical; + position: absolute; + right: -1px; + top: 100%; + z-index: @z-index-5 - 2; + + ._active & { + display: block; } +} - .message { +.message-system-action-dropdown { + .lib-button-reset(); + float: right; + margin: @message-system-short__padding-vertical 0; + position: relative; + + .action-toggle-triangle ( + @_dropdown__padding-right: @message-system-triangle__padding-right; + @_triangle__height: @message-system-triangle__height; + @_triangle__width: @message-system-triangle__width; + @_triangle__color: @message-system__color; + @_triangle__hover__color: darken(@message-system__color, 10%); + @_triangle__right: (@message-system-triangle__padding-right / 2) - (@message-system-triangle__width/ 2); + ); +} + +.message-system-summary { + text-align: right; + + .action__message-log { + border-right: 1px solid @message-system__border-color; display: inline-block; - padding: @message-system-short-message__padding-vertical 2rem @message-system-short-message__padding-vertical 3.3rem; + margin: 0 .2rem 0 @indent__xs; + padding-right: @indent__xs; - &:before { - left: .3rem; + &:last-child { + border-right: 0; + margin: 0; + padding: 0; } } } + +.notices-wrapper { + .admin__data-grid-loading-mask { + display: none; + min-height: @message-system-short-wrapper__height + @message-system__border-width; + z-index: @z-index-5 - 1; + } + + .admin__data-grid-outer-wrap { + min-height: 0; + } +} diff --git a/app/design/adminhtml/Magento/backend/Magento_AdvancedCheckout/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_AdvancedCheckout/web/css/source/_module.less index 83dc788d9de04..0cd9152333598 100644 --- a/app/design/adminhtml/Magento/backend/Magento_AdvancedCheckout/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_AdvancedCheckout/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml index d26590e617c16..670fe007232e3 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/styles.xml b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/styles.xml index 48bc194d402d2..5d28e79fd66ab 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/layout/styles.xml +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/layout/styles.xml @@ -1,7 +1,7 @@ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less index f9c3b5d387e57..a6e02022eb0b5 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module.less index 5f527710b7d27..5e7a3d9ea7788 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_footer.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_footer.less index 7eaf33bb20dd3..90ff534dc83a1 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_footer.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_footer.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_header.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_header.less index dd51587ec3a76..85cdc451a6191 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_header.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_header.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_main.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_main.less index c82b4210b9fcb..d96e1bef9e819 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_main.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_main.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less index 3f788d4e94bcf..2a2c9f5d818a0 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/_menu.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_actions-group.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_actions-group.less index 4070a101c1730..a40c4ddea1eac 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_actions-group.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_actions-group.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_headings-group.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_headings-group.less index acc03d7589d3e..ef4c61330981d 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_headings-group.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/_headings-group.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less index 685bd6b8b9166..8d14af647de92 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_notifications.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_search.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_search.less index 5348a7c6b8c38..b1d080b65b630 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_search.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_search.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_user.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_user.less index 9a97661077664..a0841a2c87293 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_user.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/actions-group/_user.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/headings-group/_breadcrumbs.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/headings-group/_breadcrumbs.less index c38cdcf3ce3f4..9b402e12f2463 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/headings-group/_breadcrumbs.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/header/headings-group/_breadcrumbs.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less index 19c099d851601..eed1d9312dd8f 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_actions-bar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_collapsible-blocks.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_collapsible-blocks.less index 6e9c63f6a1469..ae6e3feaee2c5 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_collapsible-blocks.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_collapsible-blocks.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_page-nav.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_page-nav.less index 83e9170862e65..f7e8c497036c5 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_page-nav.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_page-nav.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less index f1fe3a8f31163..47bc4ca08582b 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/_store-scope.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/actions-bar/_store-switcher.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/actions-bar/_store-switcher.less index 2927879e72158..5fb55565f3592 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/actions-bar/_store-switcher.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/main/actions-bar/_store-switcher.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_cache-management.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_cache-management.less index f6caf3f87f475..bf9a74477e8c3 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_cache-management.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_cache-management.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_dashboard.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_dashboard.less index 611afd3f4d70b..0f93856ea807a 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_dashboard.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_dashboard.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less index a6fdc2f46417d..79d0cca590704 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less +++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module/pages/_login.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Banner/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Banner/web/css/source/_module.less index 3943efa743fa0..ba8bd2eb8f64d 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Banner/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Banner/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Braintree/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Braintree/web/css/source/_module.less index 690bbf5451b61..bf1709279bea9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Braintree/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Braintree/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less index 1e5665e3c6320..fbe5fbb0f9a27 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less index 304f895a85b96..3c6e778122184 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -78,3 +78,19 @@ margin-top: -@indent__base; } } + +// +// Advanced Price panel +// --------------------------------------------- + +.admin__control-fields { + .control-grouped { + .lib-vendor-prefix-display(inline-flex); + .lib-vendor-prefix-flex-direction(row); + + .admin__field + .admin__field { + margin-left: @indent__s; + margin-top: 0; + } + } +} diff --git a/app/design/adminhtml/Magento/backend/Magento_CatalogPermissions/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_CatalogPermissions/web/css/source/_module.less index c6d2fd777b084..2dabf2758b122 100644 --- a/app/design/adminhtml/Magento/backend/Magento_CatalogPermissions/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_CatalogPermissions/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Config/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Config/web/css/source/_module.less index 6649c3f7e6fb0..78e6423f869d8 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Config/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Config/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less index 74591a1f905a8..71ad4e2818b9d 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module.less index 7da4ce847525e..1873fc5318c90 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_attributes_template_popup.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_attributes_template_popup.less index bbb310e501651..32b699057d727 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_attributes_template_popup.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_attributes_template_popup.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less index 94560642e7925..2a9e30b559ae7 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_currency-addon.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_grid.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_grid.less index 4877ec59dc52e..976d958a8d359 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_grid.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_grid.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_navigation-bar.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_navigation-bar.less index 91207137ee227..2c3b7ae6abcce 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_navigation-bar.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_navigation-bar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less index f05ab52e7a4bf..8a2d23a1fc174 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/_steps-wizard.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_buttons.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_buttons.less index af382dc778a01..15fafc51cfdd9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_buttons.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_buttons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_navigation-bar.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_navigation-bar.less index 2a69a3afe3b09..80625b3d834a5 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_navigation-bar.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/components/navigation-bar/_navigation-bar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_attribute-values.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_attribute-values.less index 63a0c8d102d9f..721b9f36f3a34 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_attribute-values.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_attribute-values.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less index a4b5a761ddef0..7bfd7c8e3e733 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_bulk-images.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_select-attributes.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_select-attributes.less index f234c3e11f4f9..ea1afdebb5cd9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_select-attributes.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_select-attributes.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_summary.less b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_summary.less index 8d217cbd2d5b3..0ec1cdf215e9e 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_summary.less +++ b/app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/module/steps/_summary.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_CurrencySymbol/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_CurrencySymbol/web/css/source/_module.less index c2797991f2c2a..bc51a34bec58c 100644 --- a/app/design/adminhtml/Magento/backend/Magento_CurrencySymbol/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_CurrencySymbol/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less index a6ab538f842d0..5048c630bd941 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_CustomerBalance/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_CustomerBalance/web/css/source/_module.less index be01e73977b2f..39f3c4bf33c10 100644 --- a/app/design/adminhtml/Magento/backend/Magento_CustomerBalance/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_CustomerBalance/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Developer/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Developer/web/css/source/_module-old.less index 141ce7de71581..79b4073e945bb 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Developer/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Developer/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Downloadable/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Downloadable/web/css/source/_module.less index b179528a94bbb..c4d4f67bfac33 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Downloadable/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Downloadable/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Enterprise/layout/default.xml b/app/design/adminhtml/Magento/backend/Magento_Enterprise/layout/default.xml index b027c2db503e3..2262c22fb5d9c 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Enterprise/layout/default.xml +++ b/app/design/adminhtml/Magento/backend/Magento_Enterprise/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less index 3cd535f42d2cc..1c6b03e6412bf 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_GiftCard/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_GiftCard/web/css/source/_module.less index 8e09d1ffd89f1..0a80140359fff 100644 --- a/app/design/adminhtml/Magento/backend/Magento_GiftCard/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_GiftCard/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less index 15d2e0bf89b5e..046dd40b5fbe8 100644 --- a/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module.less index fcd0382ec6f88..c06dcfa233c46 100644 --- a/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_GiftRegistry/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_GiftWrapping/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_GiftWrapping/web/css/source/_module.less index 116878bb19134..4c5debf646b20 100644 --- a/app/design/adminhtml/Magento/backend/Magento_GiftWrapping/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_GiftWrapping/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Integration/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Integration/web/css/source/_module.less index 3527cb48759e8..357cdf49f7125 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Integration/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Integration/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less index 8fc3db95de4f0..6f578c1581c63 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Marketplace/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Msrp/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Msrp/web/css/source/_module-old.less index f4bb7a7ec6c16..77740ad2c4b09 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Msrp/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Msrp/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_ProductVideo/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_ProductVideo/web/css/source/_module.less index 2ba6719f416dd..12926922857c7 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ProductVideo/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_ProductVideo/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Review/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Review/web/css/source/_module.less index 44061113e3f67..aaf2ed6a67fda 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Review/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Review/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Reward/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Reward/web/css/source/_module.less index 96735297be953..b352d569efdc4 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Reward/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Reward/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Rma/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Rma/web/css/source/_module.less index 8d038891e9be0..2fcafa94b457b 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Rma/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Rma/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/_module.less index eda8297b08265..6d0ad3ab032a6 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_edit-order.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_edit-order.less index 06c480c8cdefa..d18dd61fbb4e0 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_edit-order.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_edit-order.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less index a623fb72ffab0..d1fd92066e10a 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_address.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_address.less index 70cf4076b50a0..e6f3a0dbd2829 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_address.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_address.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_discounts.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_discounts.less index e9c60c8f871d3..4ffc898030dc0 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_discounts.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_discounts.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_gift-options.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_gift-options.less index dbe7dd4a03e53..d8c98219cbc66 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_gift-options.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_gift-options.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_items.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_items.less index e98b6c25c587b..24e1ff4a243cb 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_items.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_items.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-account.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-account.less index 7f82cf8d6e970..db27e03ab8840 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-account.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-account.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-comments.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-comments.less index 208c356407fd0..5fb6d4c649d17 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-comments.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_order-comments.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less index bb6f36b1b4ffc..f084db52bcb80 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -75,6 +75,12 @@ } } +.order-shipping-method { + .admin__page-section-title > span { + &:extend(.validation-symbol all); + } +} + .shipping-description-wrapper { .price { font-weight: @font-weight__bold; diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sidebar.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sidebar.less index 2f7b9add37d35..252ed1e2b6080 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sidebar.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sidebar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sku.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sku.less index 65a29e153b12f..879f9a891853c 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sku.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_sku.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_total.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_total.less index 746bd3b80fd03..36bcb9b540479 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_total.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_total.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Shipping/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Shipping/web/css/source/_module.less index 4bfb8d7603957..c3d2bc7c50d04 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Shipping/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Shipping/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Signifyd/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Signifyd/web/css/source/_module.less new file mode 100644 index 0000000000000..7449dce5e2ebb --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Signifyd/web/css/source/_module.less @@ -0,0 +1,13 @@ +// /** +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Order Case Info +// --------------------------------------------- + +.order-case-table { + &:extend(.abs-order-tables all); + &:extend(.abs-order-tbody-border all); +} diff --git a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less index b82da7c4b9c04..579c923268fa9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes-modal.less b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes-modal.less index 92d84de55715e..6e7b7249ec17f 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes-modal.less +++ b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes-modal.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes.less b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes.less index a0b58b688d3f9..830ec24b22d67 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes.less +++ b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_scheduled-changes.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-data-tooltip.less b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-data-tooltip.less index 76dd6eb331501..636c45dca18d7 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-data-tooltip.less +++ b/app/design/adminhtml/Magento/backend/Magento_Staging/web/css/source/module/_staging-data-tooltip.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module-old.less index b9b980f858ba9..81e7709888e1b 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module.less index 1920b36e9d8c2..955f73e523c24 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Theme/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Theme/web/css/source/_module-old.less index 1eeccd73827d1..6b57b29c3ba36 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Theme/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Theme/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Translation/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Translation/web/css/source/_module.less index c49a3982116ef..33766ec33476d 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Translation/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Translation/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less index 400a6d65e3016..f0a5c67c6b3d8 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module.less index b138e24a290f0..0cea72f40ee71 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less index 7148ed87437ad..906d7c1f89753 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/_data-grid.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-header.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-header.less index dd99a56e19b6c..4cbd4e987bf5f 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-header.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-header.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-static.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-static.less index 2a9b829c90281..0b512c9e58b71 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-static.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/_data-grid-static.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less index 5c99335037392..d4336811a715c 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-bookmarks.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-columns.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-columns.less index 34c5b36af1a84..40395b1a81c05 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-columns.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-columns.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-export.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-export.less index ff269a39596a7..10a694e6fd585 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-export.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-action-export.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less index ddfe72dc0b215..32fa61b678b74 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-filters.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-pager.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-pager.less index 51b67ac1a8400..c5ee57210239e 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-pager.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-pager.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-sticky-header.less b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-sticky-header.less index 2def336fbce61..82933f8d8c1e9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-sticky-header.less +++ b/app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/module/data-grid/data-grid-header/_data-grid-sticky-header.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_Vault/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Vault/web/css/source/_module.less index b7c3fce67aa5b..cfdd9dfd60399 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Vault/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Vault/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_VersionsCms/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_VersionsCms/web/css/source/_module.less index 6a041ac02f51f..4653e12618114 100644 --- a/app/design/adminhtml/Magento/backend/Magento_VersionsCms/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_VersionsCms/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less index 2aab348e6db02..c3a2e841655b0 100644 --- a/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_VisualMerchandiser/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/composer.json b/app/design/adminhtml/Magento/backend/composer.json index 29569db622d2c..ff0eda055bba6 100644 --- a/app/design/adminhtml/Magento/backend/composer.json +++ b/app/design/adminhtml/Magento/backend/composer.json @@ -2,7 +2,7 @@ "name": "magento/theme-adminhtml-backend", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/framework": "100.2.*" }, "type": "magento2-theme", diff --git a/app/design/adminhtml/Magento/backend/etc/view.xml b/app/design/adminhtml/Magento/backend/etc/view.xml index b93e179c087bf..de6b0cfab6961 100644 --- a/app/design/adminhtml/Magento/backend/etc/view.xml +++ b/app/design/adminhtml/Magento/backend/etc/view.xml @@ -1,7 +1,7 @@ diff --git a/app/design/adminhtml/Magento/backend/registration.php b/app/design/adminhtml/Magento/backend/registration.php index a06d0fb85dcbd..c656167f4d5cc 100644 --- a/app/design/adminhtml/Magento/backend/registration.php +++ b/app/design/adminhtml/Magento/backend/registration.php @@ -1,6 +1,6 @@ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/_setup.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/_setup.less index 23154cdb87875..a0b76d73450c0 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/_setup.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/_setup.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_messages.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_messages.less index e3c6218f9ca63..c191c5c9a6cfd 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_messages.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_messages.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_navigation-bar.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_navigation-bar.less index 30704e1d477e6..d8c44319a9804 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_navigation-bar.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_navigation-bar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_progress-bars.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_progress-bars.less index c35461b7ab750..d099de27fc5b7 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_progress-bars.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_progress-bars.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_tooltips.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_tooltips.less index b57fa55cd5346..48f06557632e3 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_tooltips.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/_tooltips.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_password-strength.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_password-strength.less index 5b31743ebfc9c..26e5afdbd51c8 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_password-strength.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_password-strength.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_tooltips.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_tooltips.less index 3121e76890ba1..10b57bdf00e7b 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_tooltips.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/components/tooltips/_tooltips.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less index f7162caa9ee91..08c6560cce70a 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_buttons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_classes.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_classes.less index 1bb50e10a0ebb..ee89253146af4 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_classes.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_classes.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_collector.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_collector.less index 1be4d55004078..1ebce70f04bf6 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_collector.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_collector.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_extends.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_extends.less index 946621a745515..b40a5eb4dc5d9 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_extends.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_extends.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_forms.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_forms.less index a28622f3a1a6b..0387a9df35da8 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_forms.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_forms.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_icons.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_icons.less index 70d04da600244..b0d6a31852ac0 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_icons.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_icons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_lists.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_lists.less index d706faac91ac4..78e44cb749c4c 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_lists.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_lists.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_structures.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_structures.less index d79824188a143..ba5f84377967e 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_structures.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_structures.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_utilities.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_utilities.less index fd2e7fa215e71..8b28bf5b276ce 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_utilities.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_utilities.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_variables.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_variables.less index e7a527c45cf93..49d773405585e 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_variables.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/_variables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_checkbox-radio.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_checkbox-radio.less index 23621ea8cc58a..163250e1acf29 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_checkbox-radio.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_checkbox-radio.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_forms.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_forms.less index 1ce8ad09ecdbb..d33e5eea64307 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_forms.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_forms.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_legends.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_legends.less index 2ffd46cccdce1..bb21cd2788fb3 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_legends.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_legends.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_multiselects.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_multiselects.less index 2e99b9998fe21..c87da08c24ae2 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_multiselects.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_multiselects.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less index 4c520f982887f..4a78b19efbb2b 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_selects.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_validation.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_validation.less index 357b7f2248b1c..1c02552681aee 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_validation.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/forms/_validation.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_animations.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_animations.less index fa759e34f4f84..ff12a62db2a79 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_animations.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_animations.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid-framework.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid-framework.less index 2f89fa422fab2..069cbd74aee20 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid-framework.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid-framework.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid.less index 81d91e55518ba..99eabee853a0f 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_grid.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_vendor-prefixes.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_vendor-prefixes.less index 63ce8c239568e..5f270518b9645 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_vendor-prefixes.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/lib/utilities/_vendor-prefixes.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less index 2d3284629d0ff..a965eb552ad34 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_common.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_customize-your-store.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_customize-your-store.less index 8f5854cafc2b7..326e5db30df76 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_customize-your-store.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_customize-your-store.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_install.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_install.less index b6cff635fc211..6e5ddedf7f593 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_install.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_install.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_landing.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_landing.less index 410e01c461470..00d52c4af0868 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_landing.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_landing.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_license.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_license.less index d3ee5467f245b..8463929f3e61d 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_license.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_license.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_readiness-check.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_readiness-check.less index a52fb94cbbd22..c5bf7b57f1182 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_readiness-check.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_readiness-check.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_web-configuration.less b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_web-configuration.less index cc3cec2cd520d..2fd977f2cbbaf 100644 --- a/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_web-configuration.less +++ b/app/design/adminhtml/Magento/backend/web/app/setup/styles/less/pages/_web-configuration.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_data-grid.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_data-grid.less index 9e2e7037b0e0e..31db8cba7221f 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_data-grid.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_data-grid.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_header.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_header.less index bf4270eb3e4ab..31953ff54f976 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_header.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_header.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_menu.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_menu.less index 4d0fe89bc9c74..7c821c6e0ca5b 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_menu.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_menu.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_modals.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_modals.less index b1cc0f6ea22dc..61bd4a8675849 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_modals.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_modals.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_navigation-bar_extend.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_navigation-bar_extend.less index 905e508da479a..1ba8b070e8eb6 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_navigation-bar_extend.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_navigation-bar_extend.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_page-inner.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_page-inner.less index e8fb19ba53a43..7e1c780e4719e 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_page-inner.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/components/_page-inner.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_common.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_common.less index 5a2f0733de77f..a853893080089 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_common.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_common.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_extension-manager.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_extension-manager.less index 33d12df48ba2d..fab34ab95427d 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_extension-manager.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_extension-manager.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_home.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_home.less index 47f99e4f859f9..15f844a27b114 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_home.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_home.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_login.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_login.less index 9c678a0c3301b..e2c3a2575b5d5 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_login.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/pages/_login.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_extends.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_extends.less index bb4c4df134ce8..7db0fa44bf76a 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_extends.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_extends.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_forms.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_forms.less index 3e5da804aaa84..1f7d2ee911f84 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_forms.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_forms.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_lists.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_lists.less index bb94028f51f42..9d19bc8aade34 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_lists.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_lists.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_structure.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_structure.less index 84b47233a99cd..383c4ffef971e 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_structure.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_structure.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_typography.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_typography.less index b49e5b752eaef..e3c00bbc05d5f 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_typography.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_typography.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_variables.less b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_variables.less index 9bcb0cdff6460..a9e6a66cd8316 100644 --- a/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_variables.less +++ b/app/design/adminhtml/Magento/backend/web/app/updater/styles/less/source/_variables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_actions.less b/app/design/adminhtml/Magento/backend/web/css/source/_actions.less index 63c0727f1d0ed..388a74a7b2e23 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_actions.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_actions.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_classes.less b/app/design/adminhtml/Magento/backend/web/css/source/_classes.less index 6caff93cf4784..78aff58bc99a9 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_classes.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_classes.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_components.less b/app/design/adminhtml/Magento/backend/web/css/source/_components.less index 404e231eb56c0..f4908b7b50b55 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_components.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_components.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_extends.less b/app/design/adminhtml/Magento/backend/web/css/source/_extends.less index ff973995d7599..0cf492568f9d7 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_extends.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_extends.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_forms.less b/app/design/adminhtml/Magento/backend/web/css/source/_forms.less index 2437ebeb411a9..10d5048141411 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_forms.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_forms.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_grid.less b/app/design/adminhtml/Magento/backend/web/css/source/_grid.less index 907ac6fc47bd5..319a090b3ebfd 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_grid.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_grid.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_icons.less b/app/design/adminhtml/Magento/backend/web/css/source/_icons.less index 0b3b9f95291d1..4230b371c31fe 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_icons.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_icons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_lists.less b/app/design/adminhtml/Magento/backend/web/css/source/_lists.less index 01186da68acdc..89ab2f180391b 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_lists.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_lists.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_reset.less b/app/design/adminhtml/Magento/backend/web/css/source/_reset.less index 9fec0f3459a56..7a11abd3eb803 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_reset.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_reset.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_responsive.less b/app/design/adminhtml/Magento/backend/web/css/source/_responsive.less index 80f0cd02f1597..4b594a952a296 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_responsive.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_responsive.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_sources.less b/app/design/adminhtml/Magento/backend/web/css/source/_sources.less index 14ef3bbcf35ef..bc5b04e8d8366 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_sources.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_sources.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_structure.less b/app/design/adminhtml/Magento/backend/web/css/source/_structure.less index b9023feed29a8..d180f910f56b5 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_structure.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_structure.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_tables.less b/app/design/adminhtml/Magento/backend/web/css/source/_tables.less index cfe767dde307d..5d99d78ce78b7 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_tables.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_tables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_tabs.less b/app/design/adminhtml/Magento/backend/web/css/source/_tabs.less index 5a0ffc3ad63e9..fd10fda3b338d 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_tabs.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_tabs.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_theme.less b/app/design/adminhtml/Magento/backend/web/css/source/_theme.less index cc64e88cf1717..a7849e116770a 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_theme.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_theme.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_typography.less b/app/design/adminhtml/Magento/backend/web/css/source/_typography.less index a325e142ecfaf..99e16269103f7 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_typography.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_typography.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_utilities.less b/app/design/adminhtml/Magento/backend/web/css/source/_utilities.less index 2b849725d57dc..24fbde3024ab7 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_utilities.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_utilities.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_variables.less b/app/design/adminhtml/Magento/backend/web/css/source/_variables.less index 2a5ea26e9d975..7a97010da71bb 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_variables.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_variables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less index 62e9532bae072..d7b1152128204 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-dropdown.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multicheck.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multicheck.less index 80cabe993da79..6699818864afd 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multicheck.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multicheck.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multiselect.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multiselect.less index 7dbbda3e9b744..707880d2f428b 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multiselect.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-multiselect.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less index 88440254d7a44..bf28f3b244464 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-select.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less index 1337ae18a488e..885c6594ebeb8 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-split.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less index f48a7f6f882a8..c45a64fc57187 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/actions/_actions-switcher.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_calendar-temp.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_calendar-temp.less index 2a8b478cb00d9..dc80e6d894e61 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_calendar-temp.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_calendar-temp.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_data-tooltip.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_data-tooltip.less index 458157b8ad3e9..ac76a4fa11693 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_data-tooltip.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_data-tooltip.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less index 7c08dc1cb931c..d609179dd13ff 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-insertion.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less index 7637e64d830d1..879f6adb15ffe 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_file-uploader.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -15,6 +15,17 @@ @file-uploader-preview__background-color: @color-white; @file-uploader-preview-focus__color: @color-blue2; +@file-uploader-document-icon__color: @color-gray80; +@file-uploader-document-icon__size: 7rem; +@file-uploader-document-icon__z-index: @data-grid-file-uploader-image__z-index + 1; + +@file-uploader-video-icon__color: @color-gray80; +@file-uploader-video-icon__size: 4rem; +@file-uploader-video-icon__z-index: @data-grid-file-uploader-image__z-index + 1; + +@file-uploader-placeholder-icon__color: @color-gray80; +@file-uploader-placeholder-icon__z-index: @data-grid-file-uploader-image__z-index + 1; + @file-uploader-delete-icon__color: @color-brownie; @file-uploader-delete-icon__hover__color: @color-brownie-vanilla; @file-uploader-delete-icon__font-size: 2rem; @@ -48,7 +59,6 @@ // --------------------------------------------- .file-uploader-area { - margin-bottom: @indent__xs; position: relative; input[type='file'] { @@ -66,6 +76,11 @@ } } +.file-uploader-summary { + display: inline-block; + vertical-align: top; +} + .file-uploader-button { cursor: pointer; display: inline-block; @@ -89,17 +104,6 @@ } .file-uploader-preview { - background: @file-uploader-preview__background-color; - border: 1px solid @file-uploader-preview__border-color; - box-sizing: border-box; - cursor: pointer; - height: @file-uploader-preview__height; - line-height: 1; - margin-bottom: @indent__s; - overflow: hidden; - position: relative; - width: @file-uploader-preview__width; - .action-remove { &:extend(.abs-action-reset all); .lib-icon-font ( @@ -123,12 +127,18 @@ } &:hover { - .preview-image { + .preview-image img, + .preview-link:before { opacity: @file-uploader-preview__opacity; } } - .preview-image { + .preview-link { + display: block; + height: 100%; + } + + .preview-image img { bottom: 0; left: 0; margin: auto; @@ -139,6 +149,59 @@ top: 0; z-index: 1; } + + .preview-video { + .lib-icon-font( + @icon-video__content, + @_icon-font: @icons-admin__font-name, + @_icon-font-size: @file-uploader-video-icon__size, + @_icon-font-color: @file-uploader-video-icon__color, + @_icon-font-color-hover: @file-uploader-video-icon__color + ); + + &:before { + left: 0; + margin-top: -@file-uploader-video-icon__size / 2; + position: absolute; + right: 0; + top: 50%; + z-index: @file-uploader-video-icon__z-index; + } + } + + .preview-document { + .lib-icon-font( + @icon-document__content, + @_icon-font: @icons-admin__font-name, + @_icon-font-size: @file-uploader-document-icon__size, + @_icon-font-color: @file-uploader-document-icon__color, + @_icon-font-color-hover: @file-uploader-document-icon__color + ); + + &:before { + left: 0; + margin-top: -@file-uploader-document-icon__size / 2; + position: absolute; + right: 0; + top: 50%; + z-index: @file-uploader-document-icon__z-index; + } + } +} + +.file-uploader-preview, +.file-uploader-placeholder { + background: @file-uploader-preview__background-color; + border: 1px solid @file-uploader-preview__border-color; + box-sizing: border-box; + cursor: pointer; + display: block; + height: @file-uploader-preview__height; + line-height: 1; + margin: @indent__s @indent__m @indent__s 0; + overflow: hidden; + position: relative; + width: @file-uploader-preview__width; } .file-uploader { @@ -154,6 +217,8 @@ } .file-uploader-filename { + .lib-text-overflow(); + max-width: @file-uploader-preview__width; word-break: break-all; &:first-child { @@ -176,6 +241,76 @@ } } +// Placeholder for multiple uploader +.file-uploader-placeholder { + &.placeholder-document { + .lib-icon-font( + @icon-document__content, + @_icon-font: @icons-admin__font-name, + @_icon-font-size: 5rem, + @_icon-font-color: @file-uploader-placeholder-icon__color, + @_icon-font-color-hover: @file-uploader-placeholder-icon__color + ); + + &:before { + left: 0; + position: absolute; + right: 0; + top: 20px; + z-index: @file-uploader-placeholder-icon__z-index; + } + } + + &.placeholder-image { + .lib-icon-font( + @icon-camera__content, + @_icon-font: @icons-admin__font-name, + @_icon-font-size: 5rem, + @_icon-font-color: @file-uploader-placeholder-icon__color, + @_icon-font-color-hover: @file-uploader-placeholder-icon__color + ); + + &:before { + left: 0; + position: absolute; + right: 0; + top: 20px; + z-index: @file-uploader-placeholder-icon__z-index; + } + } + + &.placeholder-video { + .lib-icon-font( + @icon-video__content, + @_icon-font: @icons-admin__font-name, + @_icon-font-size: 3rem, + @_icon-font-color: @file-uploader-placeholder-icon__color, + @_icon-font-color-hover: @file-uploader-placeholder-icon__color + ); + + &:before { + left: 0; + position: absolute; + right: 0; + top: 30px; + z-index: @file-uploader-placeholder-icon__z-index; + } + } +} + +.file-uploader-placeholder-text { + bottom: 0; + color: @color-blue-dodger; + font-size: 1.1rem; + left: 0; + line-height: @line-height__base; + margin-bottom: 15%; + padding: 0 @indent__base; + position: absolute; + right: 0; + text-align: center; +} + // // Grid image uploader // --------------------------------------------- diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less index 32c0496c90c93..b1d87e42cccee 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_media-gallery.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less index 9d9a4cab99047..ce16cc145a0c6 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_messages.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -28,6 +28,9 @@ @alert-icon__warning__content: @icon-warning__content; @alert-icon__warning__color: @color-phoenix; +@alert-icon__progress__content: @icon-refresh__content; +@alert-icon__progress__color: @color-blue-dodger; + @alert-icon__success__content: @icon-check-mage__content; @alert-icon__success__color: @color-green-apple; @@ -93,6 +96,13 @@ } } +.message-progress { + &:before { + color: @alert-icon__progress__color; + content: @alert-icon__progress__content; + } +} + .message-error { background: @alert__error__background-color; diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less index 7e88ff91b857c..155b94a57d23b 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_modals_extend.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -69,7 +69,7 @@ .modal-popup { &.prompt { .prompt-message { - padding: @modal-prompt-message__padding 0; + padding-bottom: @modal-prompt-message__padding; input { width: 100%; diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups-old.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups-old.less index 8b2c77f5fb6db..54ee80e43ac20 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups-old.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less index a1257eaf99b75..d4c13d124aa58 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_popups.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_resizable-block.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_resizable-block.less index b27e9ad8e7d0c..081c9f0abe1a8 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_resizable-block.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_resizable-block.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_rules-temp.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_rules-temp.less index b9cfc890c299b..4c5da9a1cf71b 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_rules-temp.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_rules-temp.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_slider.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_slider.less index baa3f75143be2..9afcd809f3148 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_slider.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_slider.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less index 101b5a48d75ff..b450401834d69 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_spinner.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_timeline.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_timeline.less index bdc1aea0f7123..d7673d51f130e 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/components/_timeline.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_timeline.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less index f354c0d171dd2..d359244675c10 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_controls.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_extends.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_extends.less index 2dfe994d6688a..a1586083d9dce 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_extends.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_extends.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less index be4c72daaa0b8..7fa00559d6f97 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -227,7 +227,7 @@ ._required > & { > span { &:after { - color: @field-label__required__color; + color: @validation__color; content: '*'; display: inline-block; font-size: @font-size__l; diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_form-wysiwyg.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_form-wysiwyg.less index 4886b11b6a10a..be431a8257440 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_form-wysiwyg.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_form-wysiwyg.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less index 7a61304103f4e..c52cbb5703289 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less index f414b23d6c0bc..c6082a81551f1 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/controls/_checkbox-radio.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-collapsible.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-collapsible.less index 3bfcdc3cb43ef..a09c87b62f62f 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-collapsible.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-collapsible.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less index 38bf5130b54f0..3ae7e9bf31178 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_control-table.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -131,7 +131,8 @@ &._required { span { &:after { - color: @field-label__required__color; + .lib-css(margin, @form-field-label-asterisk__margin); + color: @validation__color; content: '*'; } } diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-reset.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-reset.less index 180785ed27dba..861711fa071b6 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-reset.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-reset.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less index d3ac1aa069157..97ae3a6b79118 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_actions.less b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_actions.less index 0291f2d722d4f..486e3d3a11ab7 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_actions.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_actions.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_animations.less b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_animations.less index aaa02f717ffb6..5ec01cdebd2a5 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_animations.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_animations.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less index 2ffc6aba2d5a1..d0b92b8492454 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid-framework.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less index a35ea5b2cdb03..805c093443cf3 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_grid.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_spinner.less b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_spinner.less index a88f6cc05d335..9a57d26734c75 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/utilities/_spinner.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/utilities/_spinner.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_actions.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_actions.less index 8407aaa48aee8..7d8d402abf9e8 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_actions.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_actions.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_animations.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_animations.less index 2304ae15db5d4..26fc7f642b36c 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_animations.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_animations.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_colors.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_colors.less index 3298ae0b5073c..fb6c7c08e4e48 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_colors.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_colors.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_components.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_components.less index 694d34281d407..b3649f0e0810a 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_components.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_components.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less index a6d23ec3ae23c..cf4add983d73d 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_data-grid.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_forms.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_forms.less index fd8cdc4f0945e..729789632aace 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_forms.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_forms.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -16,7 +16,6 @@ @field-label__disabled__color: @color-gray65-almost; @field-label__font-size: @font-size__base; @field-label__line-height: @line-height__s; -@field-label__required__color: @color-phoenix; @field-note__color: @color-very-dark-gray-black; @field-note__font-size: @font-size__s; @field-scope__color: @color-dark-gray; @@ -69,7 +68,6 @@ @field-label__indent: 1rem; @field-label__disabled__color: @color-gray60; -@field-label__required__color: @color-phoenix; @field-collapsible__border-color: @color-gray80; diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less index 53433d3c75703..1c90bfc0080cb 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_icons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -80,3 +80,4 @@ @icon-clip__content: '\e643'; @icon-module__content: '\e647'; @icon-alert-round__content: '\e648'; +@icon-document__content: '\e649'; diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_spinner.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_spinner.less index d021c6578a5dc..77831c900ef9e 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_spinner.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_spinner.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less index 64cbf53dc6720..c52b6bc1dab15 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_structure.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/source/variables/_typography.less b/app/design/adminhtml/Magento/backend/web/css/source/variables/_typography.less index f11841ce84a1c..cdcfedd7d83a0 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/variables/_typography.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/variables/_typography.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/css/styles-old.less b/app/design/adminhtml/Magento/backend/web/css/styles-old.less index 2454f6b33f658..d8c894788dd82 100644 --- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less +++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -744,6 +744,7 @@ // -------------------------------------- fieldset { + min-width: 0; padding: 20px; } @@ -1412,7 +1413,7 @@ span { &:after { - color: #eb5202; + color: #e22626; content: '*'; display: inline-block; font-size: 1.6rem; @@ -5049,6 +5050,10 @@ } } } + + .admin__control-table-wrapper { + clear: both; + } } .catalog-product-set-index { diff --git a/app/design/adminhtml/Magento/backend/web/css/styles.less b/app/design/adminhtml/Magento/backend/web/css/styles.less index 247f74272dab5..f346fc971a8c4 100644 --- a/app/design/adminhtml/Magento/backend/web/css/styles.less +++ b/app/design/adminhtml/Magento/backend/web/css/styles.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot index 5bc0bee548c35..9587f3997440e 100755 Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.eot differ diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg index 4478010abc66d..2904f02b748e4 100755 --- a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg +++ b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.svg @@ -1 +1 @@ - \ No newline at end of file +Generated by IcoMoon \ No newline at end of file diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf index bc3eddf307438..2d896e8b3dba0 100755 Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.ttf differ diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff index bd9560bf58327..7cd73320aed86 100755 Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff differ diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2 b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2 index 25c1c88c0bff8..a26908a3b1e69 100755 Binary files a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2 and b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/admin-icons.woff2 differ diff --git a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json index c1733d650bcd2..f639e5bb413f1 100755 --- a/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json +++ b/app/design/adminhtml/Magento/backend/web/fonts/admin-icons/selection.json @@ -1,2326 +1,2356 @@ { - "IcoMoonType": "selection", - "icons": [ - { - "icon": { - "paths": [ - "M2041.366 1.102v1021.449h-175.926l-411.263-409.297v-204.59l411.263-407.568h175.926z", - "M1305.997 989.076c0 19.377-15.608 34.924-34.856 34.924h-1236.279c-19.255 0-34.863-15.547-34.863-34.924v-954.275c0-19.248 15.608-34.801 34.863-34.801h1236.279c19.248 0 34.856 15.553 34.856 34.801v954.275z" - ], - "width": 2041, - "attrs": [], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "video" - ], - "grid": 0 - }, - "attrs": [], - "properties": { - "order": 127, - "id": 0, - "prevSize": 32, - "code": 58945, - "name": "video" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 0 - }, - { - "icon": { - "paths": [ - "M723.661 889.601c-2.404-10.843-4.034-21.47-5.282-31.583h-277.528c-2.458 20.233-6.917 43.087-14.646 64.305-7.79 21.277-18.796 40.54-33.824 54.15-15.028 13.552-33.689 22.104-59.788 22.158v25.369h494.020v-25.369c-26.142-0.058-44.737-8.61-59.838-22.158-22.44-20.307-35.961-53.91-43.114-86.873zM1126.214 0h-1093.209c-18.22 0-33.005 15.024-33.005 33.596v731.259c0 18.576 14.785 33.623 33.005 33.623h1093.209c18.224 0 33.067-15.051 33.067-33.623v-731.259c0-18.572-14.843-33.596-33.067-33.596zM1079.193 716.922h-999.234v-635.394h999.234v635.394z" - ], - "width": 1159, - "attrs": [], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "screen" - ], - "grid": 0 - }, - "attrs": [], - "properties": { - "order": 72, - "id": 1, - "prevSize": 32, - "code": 58944, - "name": "screen" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 1 - }, - { - "icon": { - "paths": [ - "M771.001 776.737c-55.445 0-100.448 44.754-100.448 100.2s44.879 100.324 100.448 100.324 100.448-44.879 100.448-100.324-45.003-100.2-100.448-100.2zM771.001 918.707c-23.123 0-41.77-18.648-41.77-41.771s18.647-41.77 41.77-41.77c23.247 0 41.895 18.648 41.895 41.77s-18.648 41.771-41.895 41.771z", - "M469.532 776.737c-55.445 0-100.449 44.754-100.449 100.2s45.003 100.324 100.449 100.324c55.445 0 100.448-44.879 100.448-100.324s-45.003-100.2-100.448-100.2zM469.532 918.707c-23.123 0-41.771-18.648-41.771-41.771s18.648-41.77 41.771-41.77 41.77 18.648 41.77 41.77-18.648 41.771-41.77 41.771z", - "M823.587 494.412c-130.036 0-238.441-91.622-264.547-213.825h-207.237l-136.749-198.162v-1.865h-207.237v83.541h169.942l78.693 117.729 83.417 412.857h581.183l49.23-243.786c-42.268 27.474-92.616 43.511-146.694 43.511z", - "M1023.862 249.756v-45.376l-55.073-18.026-12.929-31.204 24.863-52.71-31.95-32.074-5.967 2.984-45.5 23.123-31.328-12.929-19.642-54.948h-45.376l-2.114 6.464-15.912 48.608-31.203 12.929-52.835-24.863-32.074 31.95 3.108 5.967 23.247 45.624-13.053 31.328-54.948 19.766v45.376l6.34 2.113 48.732 15.788 12.929 31.204-24.863 52.71 32.074 32.074 6.092-3.108 45.376-22.999 31.328 12.929 19.642 54.824h45.376l2.113-6.464 15.913-48.359 31.203-12.929 52.71 24.988 32.198-32.074-3.108-6.092-23.247-45.624 12.929-31.203 54.948-19.766zM824.582 291.527c-35.057 0-63.65-28.469-63.65-63.526 0-35.182 28.469-63.526 63.65-63.526s63.526 28.469 63.526 63.526c-0.124 35.182-28.469 63.526-63.526 63.526z" - ], - "attrs": [], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "cart" - ], - "grid": 0 - }, - "attrs": [], - "properties": { - "order": 71, - "id": 2, - "prevSize": 32, - "code": 58943, - "name": "cart" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 2 - }, - { - "icon": { - "paths": [ - "M0.010 188.484h1023.966v136.509h-1023.966z", - "M0.010 442.47h1023.966v136.506h-1023.966z", - "M0.010 699.017h1023.966v136.513h-1023.966z" - ], - "attrs": [ - {}, - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "list-menu" - ], - "grid": 0 - }, - "attrs": [ - {}, - {}, - {} - ], - "properties": { - "order": 61, - "id": 3, - "prevSize": 32, - "code": 58942, - "name": "list-menu" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 3 - }, - { - "icon": { - "paths": [ - "M0.010 0.372h279.074v279.074h-279.074z", - "M372.77 0.372h279.074v279.074h-279.074z", - "M744.892 0.372h279.074v279.074h-279.074z", - "M0.010 372.497h279.074v279.074h-279.074z", - "M372.77 372.497h279.074v279.074h-279.074z", - "M744.892 372.497h279.074v279.074h-279.074z", - "M0.010 744.585h279.074v279.074h-279.074z", - "M372.77 744.585h279.074v279.074h-279.074z", - "M744.892 744.585h279.074v279.074h-279.074z" - ], - "attrs": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "grid" - ], - "grid": 0 - }, - "attrs": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ], - "properties": { - "order": 112, - "id": 4, - "prevSize": 32, - "code": 58941, - "name": "grid" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 4 - }, - { - "icon": { - "paths": [ - "M982.767 231.902h-250.095l-59.255-121.364c0 0-11.827-25.201-42.11-25.201-23.375 0-169.366 0-235.25 0-32.969 0-44.001 25.027-44.001 25.027l-57.484 121.539h-253.406c-22.74 0-41.131 18.459-41.131 41.267v624.333c0 22.743 18.401 41.199 41.131 41.199h941.636c22.74 0 41.199-18.459 41.199-41.199v-624.299c0-22.798-18.456-41.267-41.199-41.267zM512 823.91c-138.793 0-251.597-113.015-251.597-251.931 0-138.912 112.845-251.87 251.597-251.87 138.68 0 251.597 112.981 251.597 251.87 0 138.909-112.913 251.931-251.597 251.931z", - "M512 420.932c-83.255 0-150.972 67.714-150.972 150.972 0 83.197 67.71 150.903 150.972 150.903 83.258 0 150.903-67.714 150.903-150.903 0-83.255-67.652-150.972-150.903-150.972z" - ], - "attrs": [ - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "camera" - ], - "grid": 0 - }, - "attrs": [ - {}, - {} - ], - "properties": { - "order": 121, - "id": 5, - "prevSize": 32, - "code": 58940, - "name": "camera" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 5 - }, - { - "icon": { - "paths": [ - "M904.192 0.027l-307.234 0.116-596.89 596.958 426.906 426.906 596.958-596.958-0.113-305.596-119.603-121.426zM858.679 313.337c-39.997 40.001-104.854 40.001-144.794 0-40.001-40.001-40.001-104.796 0-144.794 39.939-40.001 104.796-40.001 144.794 0 39.997 39.997 39.997 104.793 0 144.794z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "tag" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 111, - "id": 6, - "prevSize": 32, - "code": 58939, - "name": "tag" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 6 - }, - { - "icon": { - "paths": [ - "M1094.391 77.71l-77.71-77.71-423.329 423.347-423.33-423.347-77.71 77.672 423.35 423.368-423.312 423.329 77.672 77.71 423.338-423.338 423.283 423.3 77.671-77.71-423.263-423.281z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "colorPermutations": { - "6868681": [ - { - "f": 0 - } - ] - }, - "tags": [ - "close-mage" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 110, - "id": 7, - "prevSize": 32, - "code": 58927, - "name": "close-mage" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 7 - }, - { - "icon": { - "paths": [ - "M857.675 289.413l-403.18-240.514-402.726 240.514v457.026l403.18 240.515 402.726-240.514v-457.027zM454.857 864.465l-298.427-178.383v-335.966l298.157-178.729 298.428 178.383v335.966l-298.158 178.729z" - ], - "width": 903, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "colorPermutations": { - "6868681": [ - { - "f": 0 - } - ] - }, - "tags": [ - "menu-item" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 109, - "id": 8, - "prevSize": 32, - "code": 58938, - "name": "menu-item" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 8 - }, - { - "icon": { - "paths": [ - "M505.704 40.998c-260.096 3.489-468.158 217.202-464.706 477.336 3.489 259.982 217.202 468.12 477.298 464.631s468.158-217.202 464.706-477.336c-3.413-260.058-217.202-468.12-477.298-464.631zM557.928 197.973c47.863 0 62.009 27.762 62.009 59.544 0 39.671-31.782 76.383-86.016 76.383-45.359 0-66.901-22.831-65.65-60.53 0-31.782 26.624-75.435 89.657-75.435zM435.162 806.381c-32.73 0-56.661-19.873-33.792-107.217l37.547-154.814c6.485-24.841 7.585-34.778 0-34.778-9.785 0-52.262 17.143-77.407 34.057l-16.346-26.776c79.607-66.446 171.16-105.472 210.375-105.472 32.73 0 38.153 38.722 21.807 98.266l-43.008 162.816c-7.585 28.786-4.286 38.722 3.262 38.722 9.785 0 41.984-11.871 73.614-36.75l18.47 24.841c-77.369 77.369-161.792 107.179-194.56 107.179z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "info" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 108, - "id": 9, - "prevSize": 32, - "code": 58906, - "name": "info" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 9 - }, - { - "icon": { - "paths": [ - "M591.986 448.019h-16.005v-192.019c0-105.851-86.13-192.019-192.019-192.019h-128c-105.851 0-192.019 86.13-192.019 192.019v192.019h-16.005c-26.396 0-48.014 21.618-48.014 48.014v479.991c0 26.396 21.618 48.014 48.014 48.014h544.009c26.396 0 48.014-21.618 48.014-48.014v-479.991c0-26.396-21.618-48.014-48.014-48.014zM384 896h-128l27.838-139.188c-16.801-11.529-27.838-30.872-27.838-52.793 0-35.347 28.672-64.019 64.019-64.019s64.019 28.672 64.019 64.019c0 21.921-11.036 41.263-27.838 52.793l27.838 139.188zM448.019 448.019h-256v-192.019c0-35.271 28.71-64.019 64.019-64.019h128c35.271 0 64.019 28.71 64.019 64.019v192.019z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "lock" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 107, - "id": 10, - "prevSize": 32, - "code": 58907, - "name": "lock" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 10 - }, - { - "icon": { - "paths": [ - "M870.4 317.44h-194.56v143.36h153.6v215.040h-634.88v-215.040h215.040v112.64l204.8-184.32-204.8-184.32v112.64h-256c-56.51 0-102.4 45.815-102.4 102.4v296.96c0 56.51 45.89 102.4 102.4 102.4h716.8c56.585 0 102.4-45.89 102.4-102.4v-296.96c0-56.585-45.815-102.4-102.4-102.4z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "loop" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 106, - "id": 11, - "prevSize": 32, - "code": 58908, - "name": "loop" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 11 - }, - { - "icon": { - "paths": [ - "M991.991 384h-351.991v-351.991c0-17.673-14.336-32.009-32.009-32.009h-192.019c-17.673 0-32.009 14.336-32.009 32.009v351.991h-351.991c-17.673 0-32.009 14.336-32.009 32.009v192.019c0 17.673 14.336 32.009 32.009 32.009h351.991v351.991c0 17.673 14.336 32.009 32.009 32.009h192.019c17.673 0 32.009-14.336 32.009-32.009v-351.991h351.991c17.673 0 32.009-14.336 32.009-32.009v-192.019c0-17.673-14.336-32.009-32.009-32.009z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "plus" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 105, - "id": 12, - "prevSize": 32, - "code": 58909, - "name": "plus" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 12 - }, - { - "icon": { - "paths": [ - "M505.704 40.998c-260.096 3.489-468.158 217.126-464.706 477.298 3.489 260.21 217.202 468.158 477.298 464.744 260.134-3.489 468.233-217.202 464.706-477.298-3.489-260.21-217.202-468.233-477.298-464.744zM506.577 102.4c70.163-0.986 136.382 15.853 194.56 46.118l-63.374 105.662c-38.002-18.47-80.631-28.937-125.762-28.937-45.056 0-87.723 10.43-125.687 28.975l-63.336-105.624c54.993-28.672 117.343-45.321 183.599-46.232zM254.255 637.687l-105.586 63.298c-28.672-54.955-45.321-117.305-46.194-183.486-0.986-70.201 15.853-136.457 46.118-194.56l105.624 63.45c-18.546 37.926-28.975 80.555-28.975 125.649 0 45.056 10.43 87.723 28.975 125.687zM517.461 921.562c-70.163 0.986-136.457-15.853-194.56-46.118l63.374-105.662c38.002 18.546 80.631 28.975 125.687 28.975 45.094 0 87.761-10.392 125.687-28.937l63.336 105.586c-54.993 28.634-117.305 45.246-183.561 46.194zM512 737.242c-124.397 0-225.242-100.883-225.242-225.242 0-124.397 100.883-225.28 225.242-225.28 124.473 0 225.28 100.883 225.28 225.28s-100.807 225.242-225.28 225.242zM769.745 637.687c18.546-38.002 28.975-80.631 28.975-125.687 0-45.094-10.43-87.723-28.975-125.687l105.586-63.374c28.672 54.993 45.359 117.305 46.232 183.561 0.91 70.201-15.929 136.457-46.194 194.56l-105.624-63.336z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "recover" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 104, - "id": 13, - "prevSize": 32, - "code": 58910, - "name": "recover" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 13 - }, - { - "icon": { - "paths": [ - "M906.126 135.813v0c-91.174-75.89-202.487-113.171-312.548-113.057-127.014-0.038-253.611 49.683-348.16 145.636l-95.004-79.265-1.593 305.342 300.184-56.282-99.442-82.944c67.546-64.247 155.269-97.204 244.015-97.28 79.948 0.038 159.782 26.7 226.114 81.806 84.347 70.125 127.659 170.629 127.772 272.46-0.038 14.715-0.948 29.431-2.769 44.070l137.519-26.283c0.19-5.954 0.303-11.871 0.303-17.787 0.152-140.098-60.151-279.78-176.431-376.415zM839.035 766.976c-67.736 65.498-156.255 99.025-245.912 99.1-79.986-0.038-159.82-26.738-226.114-81.806-84.347-70.125-127.697-170.629-127.772-272.498 0-16.839 1.252-33.716 3.679-50.366l-138.164 25.941c-0.379 8.116-0.683 16.346-0.683 24.462-0.114 140.174 60.226 279.817 176.545 376.491 91.136 75.852 202.411 113.057 312.51 112.981h0.341c127.924 0 255.241-50.441 349.943-147.759l90.795 75.207 0.569-305.38-299.956 57.344 104.183 86.281z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "refresh" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 113, - "id": 14, - "prevSize": 32, - "code": 58911, - "name": "refresh" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 14 - }, - { - "icon": { - "paths": [ - "M593.351 21.732c-270.753 0-490.268 219.477-490.268 490.231s219.515 490.268 490.268 490.268 490.231-219.515 490.231-490.268c0-270.753-219.477-490.231-490.231-490.231zM828.947 683.653l-72.363 72.363-162.095-162.133-164.902 164.902-73.121-73.121 164.902-164.902-161.678-161.678 72.363-72.325 161.602 161.678 165.774-165.736 73.121 73.083-165.774 165.736 162.171 162.133z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "remove-small" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 114, - "id": 15, - "prevSize": 32, - "code": 58912, - "name": "remove-small" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 15 - }, - { - "icon": { - "paths": [ - "M254.976 675.84v-267.264h103.424l-179.2-203.776-179.2 203.776h103.424v308.224c0 56.51 45.815 102.4 102.4 102.4h459.776l-131.186-143.36h-279.438zM920.538 615.424v-308.224c0-56.51-45.89-102.4-102.4-102.4h-459.738l131.11 143.36h279.514v267.264h-103.424l179.2 203.776 179.2-203.776h-103.462z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "retweet" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 117, - "id": 16, - "prevSize": 32, - "code": 58913, - "name": "retweet" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 16 - }, - { - "icon": { - "paths": [ - "M768 64.019h-128c-105.851 0-192.019 86.13-192.019 192.019v192.019h-400.005c-26.396 0-48.014 21.618-48.014 48.014v479.991c0 26.396 21.618 48.014 48.014 48.014h544.009c26.396 0 48.014-21.618 48.014-48.014v-479.991c0-26.396-21.618-48.014-48.014-48.014h-16.005v-192.019c0-35.271 28.71-64.019 64.019-64.019h128c35.271 0 64.019 28.71 64.019 64.019v192.019h128v-192.019c0-105.851-86.13-192.019-192.019-192.019zM384 896h-128l27.838-139.188c-16.801-11.529-27.838-30.872-27.838-52.793 0-35.347 28.672-64.019 64.019-64.019s64.019 28.672 64.019 64.019c0 21.921-11.036 41.263-27.838 52.793l27.838 139.188z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "unlocked" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 36, - "id": 17, - "prevSize": 32, - "code": 58914, - "name": "unlocked" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 17 - }, - { - "icon": { - "paths": [ - "M593.351 0l-593.351 1023.962h1186.74l-593.351-1023.962zM653.236 899.451h-125.421v-121.211h125.421v121.211zM622.175 728.329h-62.502l-34.816-288.313v-156.748h131.3v156.748l-33.982 288.313z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "warning" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 37, - "id": 18, - "prevSize": 32, - "code": 58915, - "name": "warning" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 18 - }, - { - "icon": { - "paths": [ - "M0 512l512 512v-320.019h512v-384h-512v-320.019z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "arrow-left" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 38, - "id": 19, - "prevSize": 32, - "code": 58916, - "name": "arrow-left" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 19 - }, - { - "icon": { - "paths": [ - "M1024 512l-512-512v320.019h-512v384h512v320.019z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "arrow-right" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 39, - "id": 20, - "prevSize": 32, - "code": 58917, - "name": "arrow-right" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 20 - }, - { - "icon": { - "paths": [ - "M402.735 146.735l-320.019 320.019c-24.993 24.993-24.993 65.498 0 90.491l320.019 320.019c24.993 24.993 65.498 24.993 90.491 0s24.993-65.498 0-90.491l-210.754-210.754h613.49c35.347 0 64.019-28.634 64.019-64.019s-28.672-64.019-64.019-64.019h-613.49l210.754-210.754c12.478-12.478 18.735-28.862 18.735-45.246s-6.258-32.768-18.735-45.246c-24.993-24.993-65.498-24.993-90.491 0z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "back-arrow" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 103, - "id": 21, - "prevSize": 32, - "code": 58918, - "name": "back-arrow" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 21 - }, - { - "icon": { - "paths": [ - "M507.259 578.522h-102.059v101.717h102.059v-101.717zM650.885 714.714h-101.945v101.717h101.945v-101.717zM507.259 714.714h-102.059v101.717h102.059v-101.717zM507.259 442.33h-102.059v101.679h102.059v-101.679zM843.131 244.091c23.4 0 42.287-18.887 42.287-42.174v-145.408c0-23.324-18.887-42.174-42.287-42.174s-42.325 18.849-42.325 42.174v145.408c0.038 23.324 18.925 42.174 42.325 42.174zM343.419 244.091c23.362 0 42.249-18.887 42.249-42.174v-145.408c0-23.324-18.887-42.174-42.249-42.174-23.4 0-42.325 18.849-42.325 42.174v145.408c0 23.324 18.925 42.174 42.325 42.174zM363.444 578.522h-102.059v101.717h102.059v-101.717zM363.444 714.714h-102.059v101.717h102.059v-101.717zM650.885 578.522h-101.945v101.717h101.945v-101.717zM938.325 578.522h-102.059v101.717h102.059v-101.717zM938.325 442.33h-102.059v101.679h102.059v-101.679zM899.337 84.385v46.914c17.598 15.474 28.71 38.153 28.71 63.412 0 46.801-37.964 84.764-84.916 84.764s-84.954-37.964-84.954-84.764c0-25.259 11.15-47.938 28.71-63.412v-46.914h-387.262v46.914c17.56 15.474 28.71 38.153 28.71 63.412 0 46.801-38.002 84.764-84.916 84.764s-84.954-37.964-84.954-84.764c0-25.259 11.15-47.938 28.71-63.412v-46.914h-192.322v925.279h997.035v-925.279h-192.512zM999.234 915.304h-809.832v-589.938h809.832v589.938zM650.885 442.33h-101.945v101.679h101.945v-101.679zM794.624 442.33h-101.983v101.679h101.983v-101.679zM794.624 714.714h-101.983v101.717h101.983v-101.717zM794.624 578.522h-101.983v101.717h101.983v-101.717z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "calendar" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 102, - "id": 22, - "prevSize": 32, - "code": 58919, - "name": "calendar" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 22 - }, - { - "icon": { - "paths": [ - "M132.21 286.758c-13.881-13.729-36.295-13.729-50.138 0-13.805 13.653-13.805 35.878 0 49.607l404.897 400.877c13.881 13.729 36.257 13.729 50.138 0l404.897-400.877c13.805-13.729 13.881-35.878 0-49.607s-36.371-13.729-50.138-0.038l-379.866 365.606-379.79-365.568z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "caret-down" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 101, - "id": 23, - "prevSize": 32, - "code": 58920, - "name": "caret-down" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 23 - }, - { - "icon": { - "paths": [ - "M737.242 891.79c13.729 13.881 13.729 36.257 0 50.138s-35.878 13.881-49.607 0l-400.877-404.821c-13.729-13.881-13.729-36.295 0-50.138l400.877-404.897c13.729-13.881 35.878-13.881 49.607 0s13.729 36.257 0 50.138l-365.568 379.79 365.568 379.79z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "caret-left" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 100, - "id": 24, - "prevSize": 32, - "code": 58921, - "name": "caret-left" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 24 - }, - { - "icon": { - "paths": [ - "M286.72 891.79c-13.729 13.881-13.729 36.257 0 50.138s35.878 13.881 49.607 0l400.877-404.821c13.729-13.881 13.729-36.295 0-50.138l-400.915-404.897c-13.729-13.881-35.878-13.881-49.607 0s-13.729 36.257 0 50.138l365.568 379.79-365.568 379.79z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "caret-right" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 99, - "id": 25, - "prevSize": 32, - "code": 58922, - "name": "caret-right" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 25 - }, - { - "icon": { - "paths": [ - "M891.79 737.242c13.881 13.729 36.295 13.729 50.138 0 13.881-13.729 13.881-35.878 0-49.607l-404.897-400.877c-13.805-13.729-36.257-13.729-50.062 0l-404.897 400.877c-13.805 13.729-13.881 35.878 0 49.607s36.257 13.729 50.138 0l379.79-365.606 379.79 365.606z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "caret-up" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 98, - "id": 26, - "prevSize": 32, - "code": 58923, - "name": "caret-up" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 26 - }, - { - "icon": { - "paths": [ - "M574.767 92.16c-227.593 0-412.672 182.386-418.247 409.335h-125.8l188.378 209.92 188.302-209.92h-146.242c5.537-168.998 143.777-304.393 313.609-304.393 173.397 0 313.913 140.971 313.913 314.899s-140.478 314.861-313.913 314.861c-69.48 0-133.689-22.718-185.685-61.099l-71.983 76.99c70.997 55.751 160.465 89.050 257.707 89.050 231.159 0 418.551-187.961 418.551-419.84-0.038-231.879-187.43-419.84-418.551-419.84z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "ccw" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 97, - "id": 27, - "prevSize": 32, - "code": 58924, - "name": "ccw" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 27 - }, - { - "icon": { - "paths": [ - "M996.617 126.786l-513.555 513.555-256.796-256.834-128.379 128.417 385.214 385.252 641.896-642.010z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "check-mage" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 96, - "id": 28, - "prevSize": 32, - "code": 58925, - "name": "check-mage" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 28 - }, - { - "icon": { - "paths": [ - "M512 40.96c-260.134 0-471.040 210.944-471.040 471.040 0 260.134 210.906 471.040 471.040 471.040s471.040-210.906 471.040-471.040c0-260.134-210.906-471.040-471.040-471.040zM512 880.64c-203.624 0-368.64-165.054-368.64-368.64s165.016-368.64 368.64-368.64 368.64 165.054 368.64 368.64-165.016 368.64-368.64 368.64zM547.84 245.76h-71.68v281.069l174.345 174.345 50.669-50.707-153.335-153.335z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "clock" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 95, - "id": 29, - "prevSize": 32, - "code": 58926, - "name": "clock" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 29 - }, - { - "icon": { - "paths": [ - "M337.541 1021.004h513.024l64.512-645.916h-639.128l61.592 645.916zM737.394 154.169v-116.508c0-19.191-15.398-34.702-34.361-34.702h-217.847c-19.001 0-34.361 15.55-34.361 34.702v114.574c-73.576 8.382-150.149 24.614-226.494 52.338v106.989h738.001v-109.833c0 0-90.074-31.403-224.977-47.559zM668.937 147.759c-47.749-3.224-99.252-4.096-153.297-0.986v-61.44c0-9.519 7.623-17.332 17.143-17.332h118.936c9.519 0 17.218 7.813 17.218 17.332v62.426z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "delete" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 94, - "id": 30, - "prevSize": 32, - "code": 58928, - "name": "delete" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 30 - }, - { - "icon": { - "paths": [ - "M928.503 26.889l-111.502 112.109 156.065 156.9 111.502-112.071-156.065-156.937zM215.002 744.41l156.065 156.9 535.211-538.093-156.065-156.9-535.211 538.093zM103.917 1007.161l188.985-49.873-139.302-140.098-49.683 190.009z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "edit" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 115, - "id": 31, - "prevSize": 32, - "code": 58929, - "name": "edit" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 31 - }, - { - "icon": { - "paths": [ - "M1014.67 822.651c0 0 0 0 0 0l-310.651-310.651 310.651-310.651c0 0 0 0 0 0 3.337-3.337 5.765-7.244 7.32-11.416 4.248-11.378 1.82-24.69-7.32-33.83l-146.735-146.735c-9.14-9.14-22.452-11.567-33.83-7.32-4.172 1.555-8.078 3.982-11.416 7.32 0 0 0 0 0 0l-310.651 310.651-310.651-310.651c0 0 0 0 0 0-3.337-3.337-7.244-5.765-11.416-7.32-11.378-4.248-24.69-1.82-33.83 7.32l-146.735 146.735c-9.14 9.14-11.567 22.452-7.32 33.83 1.555 4.172 3.982 8.078 7.32 11.416 0 0 0 0 0 0l310.651 310.651-310.651 310.651c0 0 0 0 0 0-3.337 3.337-5.765 7.244-7.32 11.416-4.248 11.378-1.82 24.69 7.32 33.83l146.735 146.735c9.14 9.14 22.452 11.567 33.83 7.32 4.172-1.555 8.078-3.982 11.416-7.32 0 0 0 0 0 0l310.651-310.651 310.651 310.651c0 0 0 0 0 0 3.337 3.337 7.244 5.765 11.416 7.32 11.378 4.248 24.69 1.82 33.83-7.32l146.735-146.735c9.14-9.14 11.567-22.452 7.32-33.83-1.555-4.172-3.982-8.078-7.32-11.416z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "error" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 122, - "id": 32, - "prevSize": 32, - "code": 58930, - "name": "error" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 32 - }, - { - "icon": { - "paths": [ - "M593.351 22.566c-270.336 0-489.434 219.098-489.434 489.358s219.098 489.434 489.434 489.434 489.434-219.136 489.434-489.434-219.136-489.358-489.434-489.358zM635.752 826.596c-11.985 11.719-26.396 17.636-43.16 17.636-8.154 0-15.967-1.517-23.4-4.589-7.358-3.034-13.843-7.168-19.456-12.174-5.613-5.158-10.126-11.226-13.388-18.356-3.337-7.13-4.968-14.753-4.968-22.945 0-16.308 5.992-30.303 17.977-42.060 11.947-11.681 26.396-17.598 43.198-17.598 16.308 0 30.606 5.689 42.78 16.801 12.25 11.188 18.318 24.993 18.318 41.339-0.038 16.384-5.992 30.303-17.939 41.984zM778.923 382.673c-3.982 13.767-9.747 26.396-17.18 37.774-7.471 11.454-16.498 22.49-27.079 33.071s-22.49 21.618-35.65 33.033c-11.454 9.785-20.783 18.318-27.913 25.79-7.168 7.396-12.895 14.867-17.218 22.338-4.286 7.433-7.282 15.398-9.026 24.007-1.707 8.609-2.617 49.721-2.617 62.35v22.338h-101.376v-32.616c0-13.729 0.986-56.661 3.034-67.584s5.158-21.125 9.481-30.872 10.012-19.228 17.18-28.369c7.168-9.14 16.232-18.887 27.079-29.203l38.647-36.902c10.847-9.747 20.177-20.632 27.951-32.616 7.737-12.060 11.529-26.7 11.529-43.88 0-22.3-6.978-41.036-21.011-56.206-14.071-15.17-33.944-22.793-59.695-22.793-13.16 0-25.069 2.389-35.65 7.282-10.619 4.817-19.797 11.454-27.496 19.759-7.737 8.344-13.577 17.901-17.598 28.786-3.982 10.847-6.334 21.997-6.865 33.527l-105.624-9.444c3.413-27.496 10.733-51.959 21.921-73.463 11.112-21.466 25.562-39.595 43.311-54.575 17.711-14.829 38.078-26.169 61.023-33.944 22.869-7.699 47.521-11.605 73.842-11.605 24.614 0 47.976 3.603 70.049 10.771 21.959 7.168 41.491 17.711 58.406 31.782 16.839 14.033 30.227 31.365 39.936 51.959 9.709 20.632 14.564 44.411 14.564 71.263 0 18.356-2.010 34.475-5.992 48.166z" - ], - "width": 1176, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "help" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 124, - "id": 33, - "prevSize": 32, - "code": 58931, - "name": "help" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 33 - }, - { - "icon": { - "paths": [ - "M574.805 92.16c-227.631 0-412.71 182.386-418.247 409.335h-125.838l188.378 209.958 188.302-209.958h-146.242c5.537-168.998 143.777-304.393 313.647-304.393 173.359 0 313.875 140.971 313.875 314.899s-140.478 314.861-313.875 314.861c-69.518 0-133.727-22.718-185.761-61.099l-71.983 76.99c71.073 55.751 160.503 89.050 257.745 89.050 231.121 0 418.513-187.961 418.513-419.84-0.038-231.879-187.43-419.84-418.513-419.84zM537.6 286.72v240.109l153.865 153.865 50.669-50.669-132.855-132.855v-210.413h-71.68z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "history" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 45, - "id": 34, - "prevSize": 32, - "code": 58932, - "name": "history" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 34 - }, - { - "icon": { - "paths": [ - "M510.413 0c-281.907 0-510.413 228.582-510.413 510.413 0 281.933 228.506 510.464 510.413 510.464s510.387-228.557 510.387-510.464c0-281.83-228.48-510.413-510.387-510.413zM865.843 510.413c0 69.99-20.506 135.27-55.578 190.285l-490.163-490.163c55.091-35.021 120.32-55.475 190.31-55.475 195.942 0 355.43 159.411 355.43 355.354zM154.957 510.413c0-69.939 20.506-135.245 55.578-190.31l490.189 490.189c-55.066 35.072-120.371 55.501-190.31 55.501-195.942 0.026-355.456-159.437-355.456-355.379z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "not-installed" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 58, - "id": 35, - "prevSize": 32, - "code": 58936, - "name": "not-installed" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 35 - }, - { - "icon": { - "paths": [ - "M511.77 0c-282.778 0-512.102 229.222-512.102 512.179 0 282.829 229.325 512.102 512.102 512.102 282.931 0.026 512.23-229.248 512.23-512.102 0-282.957-229.299-512.179-512.23-512.179zM143.718 419.968h736.205v184.269h-736.205v-184.269z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "disabled" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 57, - "id": 36, - "prevSize": 32, - "code": 58937, - "name": "disabled" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 36 - }, - { - "icon": { - "paths": [ - "M505.139 0.085c-282.658 3.775-508.826 236.066-505.071 518.827 3.772 282.556 236.1 508.826 518.793 505.003 282.658-3.768 508.826-236.066 505.071-518.827-3.717-282.658-236.1-508.826-518.793-505.003z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "dot" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 56, - "id": 37, - "prevSize": 32, - "code": 58935, - "name": "dot" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 37 - }, - { - "icon": { - "paths": [ - "M383.462 577.51h255.693v-213.043h127.795l-255.642-255.667-255.642 255.667h127.795z", - "M852.173 577.51v170.394h-681.754v-170.394h-170.419v340.89h1022.618v-340.89z" - ], - "attrs": [ - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "export" - ], - "grid": 0 - }, - "attrs": [ - {}, - {} - ], - "properties": { - "order": 93, - "id": 38, - "prevSize": 32, - "code": 58933, - "name": "export" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 38 - }, - { - "icon": { - "paths": [ - "M639.155 108.8h-255.693v213.043h-127.795l255.667 255.667 255.616-255.667h-127.795z", - "M852.173 577.51v170.394h-681.754v-170.394h-170.419v340.89h1022.618v-340.89z" - ], - "attrs": [ - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "import" - ], - "grid": 0 - }, - "attrs": [ - {}, - {} - ], - "properties": { - "order": 92, - "id": 39, - "prevSize": 32, - "code": 58934, - "name": "import" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 39 - }, - { - "icon": { - "paths": [ - "M259.2 0h214.323v214.323h-214.323v-214.323z", - "M259.2 269.875h214.323v214.349h-214.323v-214.349z", - "M259.2 539.776h214.323v214.349h-214.323v-214.349z", - "M259.2 809.651h214.323v214.349h-214.323v-214.349z", - "M549.325 0h214.323v214.323h-214.323v-214.323z", - "M549.325 269.875h214.323v214.349h-214.323v-214.349z", - "M549.325 539.776h214.323v214.349h-214.323v-214.349z", - "M549.325 809.651h214.323v214.349h-214.323v-214.349z" - ], - "attrs": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "gripper" - ], - "grid": 0 - }, - "attrs": [ - {}, - {}, - {}, - {}, - {}, - {}, - {}, - {} - ], - "properties": { - "order": 91, - "id": 40, - "prevSize": 32, - "code": 58903, - "name": "gripper" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 40 - }, - { - "icon": { - "paths": [ - "M860.058 185.062v272l-430.029-269.158-1.894 253.491-424.371-249.754-3.763 647.834 426.24-241.28-5.606 239.437 439.424-252.16v259.635h163.942v-660.045z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "forward" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 90, - "id": 41, - "prevSize": 32, - "code": 58904, - "name": "forward" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 41 - }, - { - "icon": { - "paths": [ - "M163.942 845.107v-271.974l430.029 269.133 1.894-253.491 424.397 249.754 3.738-647.834-426.24 241.28 5.606-239.437-439.424 252.16v-259.635h-163.942v660.045z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "backward" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 89, - "id": 42, - "prevSize": 32, - "code": 58905, - "name": "backward", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 42 - }, - { - "icon": { - "paths": [ - "M512.794 0c-283.187 0-512.794 229.581-512.794 512.794 0 283.187 229.606 512.794 512.794 512.794s512.794-229.632 512.794-512.794c0-283.213-229.581-512.794-512.794-512.794zM512.794 971.213c-253.158 0-458.394-205.261-458.394-458.368 0-253.158 205.261-458.394 458.394-458.394 253.184 0 458.394 205.235 458.394 458.394 0.026 253.107-205.21 458.368-458.394 458.368z", - "M760.013 625.613l30.387-38.4-265.6-206.413-20.787-1.613-259.226 208.026 28.826 39.987 236.8-177.613z" - ], - "attrs": [ - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "expand-close" - ], - "grid": 0 - }, - "attrs": [ - {}, - {} - ], - "properties": { - "order": 88, - "id": 43, - "prevSize": 32, - "code": 58901, - "name": "expand-close" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 43 - }, - { - "icon": { - "paths": [ - "M512.794 0c-283.187 0-512.794 229.581-512.794 512.794 0 283.187 229.606 512.794 512.794 512.794s512.794-229.606 512.794-512.794c0-283.213-229.581-512.794-512.794-512.794zM512.794 971.213c-253.158 0-458.394-205.261-458.394-458.394 0-253.158 205.261-458.394 458.394-458.394 253.184 0 458.394 205.235 458.394 458.394 0.026 253.133-205.21 458.394-458.394 458.394z", - "M265.6 454.4l-30.387 38.4 265.574 206.387 20.813 1.613 259.2-208-28.8-39.987-236.8 177.587z" - ], - "attrs": [ - {}, - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "expand-open" - ], - "grid": 0 - }, - "attrs": [ - {}, - {} - ], - "properties": { - "order": 87, - "id": 44, - "prevSize": 32, - "code": 58902, - "name": "expand-open" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 44 - }, - { - "icon": { - "paths": [ - "M1020.032 565.555v-116.045l-16.41-5.376-124.237-40.525-33.152-80.102 63.718-134.784-82.048-82.125-15.411 7.808-116.531 59.213-80.077-33.178-50.278-140.442h-116.096l-45.875 140.698-80 33.126-134.963-63.744-82.022 82.074 7.834 15.334 59.162 116.608-33.126 80.026-140.518 50.253v116.147l16.435 5.325 124.288 40.576 33.075 80-63.693 134.886 82.048 82.099 131.942-66.97 80.026 33.152 50.304 140.39h116.096l5.35-16.41 40.55-124.237 80.077-33.178 134.886 63.718 82.074-82.074-7.834-15.386-59.213-116.582 33.203-80.026 140.416-50.253zM510.003 672.589c-89.754 0-162.509-72.832-162.509-162.611 0-89.754 72.755-162.483 162.509-162.483 89.83 0 162.509 72.73 162.509 162.483 0.026 89.805-72.653 162.611-162.509 162.611z" - ], - "attrs": [ - { - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "system-config" - ], - "grid": 0 - }, - "attrs": [ - { - "visibility": false - } - ], - "properties": { - "order": 86, - "id": 45, - "prevSize": 32, - "code": 58896, - "name": "system-config" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 45 - }, - { - "icon": { - "paths": [ - "M509.978 54.426l-509.978 509.926 95.949 95.949 414.106-413.978 413.875 413.978 95.949-95.898-509.901-509.978zM146.253 688.563v335.437h259.917v-304.819h207.514v304.819h259.917v-335.488l-363.622-363.597-363.725 363.648z" - ], - "attrs": [ - { - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "home" - ], - "grid": 0 - }, - "attrs": [ - { - "visibility": false - } - ], - "properties": { - "order": 85, - "id": 46, - "prevSize": 32, - "code": 58897, - "name": "home" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 46 - }, - { - "icon": { - "paths": [ - "M0 736.41l498.278 287.59v-421.402l-498.278-287.667v421.478zM894.464 224.486v44.262c0 32.819-62.797 59.418-140.365 59.418-77.466 0-140.262-26.598-140.262-59.418v-73.216h0.435c4.71 30.925 65.408 55.475 139.853 55.475 77.568 0 140.365-26.624 140.365-59.29 0-32.845-62.797-59.366-140.365-59.366-6.195 0-12.262 0.205-18.202 0.563l-90.317-52.147v55.706c0 32.819-62.72 59.392-140.262 59.392-48.691 0-91.597-10.496-116.813-26.47-3.584-3.712-7.987-7.245-13.312-10.598-6.579-6.861-10.24-14.387-10.24-22.323v-53.939l-87.322 50.381c-6.272-0.307-12.646-0.614-19.123-0.614-77.491 0-140.314 26.522-140.314 59.366 0 32.691 62.822 59.29 140.314 59.29 74.445 0 135.219-24.525 139.93-55.475h0.384v73.216c0 32.819-62.746 59.418-140.314 59.418-77.491 0-140.314-26.598-140.314-59.418v-43.622l-108.083 62.31 499.994 288.563 496.691-286.694-112.358-64.768zM646.784 408.013c0 32.794-62.874 59.315-140.365 59.315s-140.339-26.522-140.339-59.315v-73.267h0.41c4.762 30.95 65.459 55.475 139.93 55.475s135.142-24.525 139.904-55.475h0.486v73.267zM525.645 606.234v417.766l498.355-287.718v-417.766l-498.355 287.718zM505.318 118.656c77.542 0 140.262-26.547 140.262-59.315s-62.72-59.315-140.262-59.315c-77.491 0-140.339 26.573-140.339 59.315-0.026 32.768 62.822 59.315 140.339 59.315z" - ], - "attrs": [ - { - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "lego" - ], - "grid": 0 - }, - "attrs": [ - { - "visibility": false - } - ], - "properties": { - "order": 84, - "id": 47, - "prevSize": 32, - "code": 58898, - "name": "lego" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 47 - }, - { - "icon": { - "paths": [ - "M287.002 481.664c0.205 0.23 0.461 0.486 0.691 0.717l103.347 103.373 36.045-36.045-56.55-56.499 90.266-90.189 11.904 1.28c3.046 0.307 6.093 0.538 9.19 0.538 6.246 0 12.314-0.768 18.253-2.125l-66.381-66.381c-1.357-1.382-2.765-2.611-4.173-3.814 20.454-73.6 1.766-155.725-56.038-213.555-57.421-57.421-138.803-76.237-211.968-56.525l123.955 123.981-32.563 121.446-121.395 32.589-124.032-124.006c-19.712 73.19-0.896 154.573 56.525 212.019 60.262 60.288 147.021 77.952 222.925 53.197zM653.235 555.802c-1.997 8.909-2.509 18.202-1.459 27.546l1.306 11.93-90.189 90.189-56.55-56.55-36.070 36.122 327.219 327.194c20.198 20.173 46.618 30.259 73.062 30.259s52.915-10.086 73.037-30.259c40.346-40.32 40.346-105.728 0-146.074l-290.355-290.355zM905.907 958.362l-51.866 13.875-42.112-42.112 13.901-51.891 51.866-13.926 42.112 42.138-13.901 51.917zM506.701 594.099l56.576 56.576 64.128-64.154c-3.482-31.334 6.707-63.821 30.669-87.808 24.013-23.962 56.474-34.176 87.808-30.72l280.397-280.346-157.056-157.056-280.448 280.397c3.482 31.258-6.682 63.821-30.669 87.782-24.013 23.987-56.525 34.176-87.808 30.643l-64.102 64.205 56.499 56.422-277.043 277.12-10.138-10.138-53.248 42.829-89.421 141.312 22.835 22.835 141.312-89.421 42.803-53.222-10.138-10.138 277.043-277.12z" - ], - "attrs": [ - { - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "tool" - ], - "grid": 0 - }, - "attrs": [ - { - "visibility": false - } - ], - "properties": { - "order": 120, - "id": 48, - "prevSize": 32, - "code": 58899, - "name": "tool" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 48 - }, - { - "icon": { - "paths": [ - "M1023.932 505.105c-3.717-282.692-236.1-508.826-518.793-505.003-282.658 3.775-508.826 236.066-505.071 518.827 3.772 282.556 236.1 508.826 518.793 505.003 282.658-3.768 508.826-236.066 505.071-518.827zM623.991 481.304v298.633h-223.983v-298.633h-186.621l298.633-298.633 298.667 298.633h-186.679z" - ], - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "upgrade" - ], - "grid": 0 - }, - "attrs": [ - {} - ], - "properties": { - "order": 125, - "id": 49, - "prevSize": 32, - "code": 58900, - "name": "upgrade" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 49 - }, - { - "icon": { - "paths": [ - "M870.821 731.837c-64.195-65.89-78.231-188.772-91.738-283.159-20.074-139.937-24.259-297.089-226.008-317.693v-25.318c0-25.424-39.195-46.028-64.937-46.028s-62.024 20.551-62.024 46.028v25.371c-200.054 20.816-206.993 177.914-226.855 317.693-13.453 94.439-27.331 217.268-91.049 283.264-12.818 13.348-16.473 32.998-9.11 49.947 7.362 16.843 24.153 27.913 42.797 27.913h695.343c18.75 0 35.593-11.070 42.903-28.019s3.655-36.653-9.322-50z", - "M489.569 963.883c51.060 0 92.373-40.837 92.373-91.367h-184.694c-0.053 50.53 41.314 91.367 92.32 91.367z" - ], - "width": 989, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "notification-02" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 123, - "id": 50, - "prevSize": 32, - "code": 58887, - "name": "notification-02" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 50 - }, - { - "icon": { - "paths": [ - "M252.137 153.228l-160.070 92.393 378.042 218.205 160.023-92.393-377.996-218.205zM845.638 247.063l-377.996-218.252-145.222 83.828 377.996 218.205 145.222-83.782zM502.784 526.15v433.664l376.832-217.507v-433.711l-376.832 217.553zM55.668 742.26l376.785 217.507v-436.503l-376.785-217.46v436.457z" - ], - "width": 954, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "product" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 7, - "id": 51, - "prevSize": 32, - "code": 58888, - "name": "product", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 51 - }, - { - "icon": { - "paths": [ - "M454.495 48.899l-402.697 240.513v457.026l104.632 60.727v-457.049l298.157-178.728 299.698 179.142-0.138 455.922 103.528-60.013v-457.026l-403.18-240.513zM507.766 330.28v534.344l-53.271 32.124-53.34-32.262v-533.792l-138.090 83.853v456.934l191.453 115.516 193.087-116.322v-456.451l-139.839-83.945z" - ], - "width": 903, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "logo" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 17, - "id": 52, - "prevSize": 32, - "code": 58886, - "name": "logo", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 52 - }, - { - "icon": { - "paths": [ - "M709.921 158.694c8.139 32.295 8.927 34.974 8.192 68.162-0.263 12.813-7.772 71.943-5.724 90.112 1.628 14.966 5.461 16.174 11.448 28.514 10.398 21.425 6.984 51.095 2.941 72.678-2.206 11.868-6.827 28.725-13.916 38.387-7.667 10.66-23.211 10.713-30.142 23.158-9.872 17.854-4.306 43.008-10.503 62.385-7.142 21.898-25.101 23.421-26.466 52.145 8.822 1.155 17.592 2.468 26.466 3.623 8.822 18.59 25.049 55.874 41.59 67.059 13.863 3.728 27.727 7.457 41.59 11.185 48.627 19.64 102.558 43.061 151.237 63.33 44.373 18.432 97.411 24.996 113.48 70.84 0 31.035 2.941 104.501 2.153 145.25h-965.553c-0.893-40.697 2.153-114.215 2.153-145.25 15.964-45.844 69.002-52.408 113.375-70.84 48.679-20.27 102.61-43.691 151.237-63.33 13.811-3.728 27.674-7.457 41.59-11.185 16.489-11.185 32.715-48.522 41.538-67.059l19.692-4.621c-4.464-24.576-19.85-26.466-26.256-43.743-2.521-26.099-5.041-52.145-7.509-78.192 0.053 1.155-18.117-3.361-20.48-4.779-25.731-15.806-26.204-80.24-28.725-107.021-1.103-12.183 16.174-22.265 11.343-44.636-28.094-131.44 12.183-192.88 75.881-213.307 44.216-17.749 126.871-50.465 203.855-3.728l19.167 17.487 30.93 5.251c15.491 8.77 25.416 38.124 25.416 38.124z" - ], - "width": 1090, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "account" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 9, - "id": 53, - "prevSize": 32, - "code": 58880, - "name": "account", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 53 - }, - { - "icon": { - "paths": [ - "M529.203 886.14l-468.465-628.209h936.931l-468.465 628.209z" - ], - "width": 1085, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "arrowdown" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 10, - "id": 54, - "prevSize": 32, - "code": 58881, - "name": "arrowdown", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 54 - }, - { - "icon": { - "paths": [ - "M976.793 982.006h-910.388v-910.388h910.388v910.388zM912.622 135.789h-782.046v782.088h782.046v-782.088z", - "M221.432 822.8h152.876v-372.033h-152.876v372.033z", - "M466.323 820.234h350.932v-366.53h-350.932v366.53z", - "M221.432 360.489h595.865v-147.125h-595.865v147.125z" - ], - "width": 1034, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "cms" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 83, - "id": 55, - "prevSize": 32, - "code": 58882, - "name": "cms", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 55 - }, - { - "icon": { - "paths": [ - "M264.319 308.831c75.685 0 136.98-61.259 136.98-136.944 0-75.649-61.295-136.98-136.98-136.98s-137.017 61.331-137.017 136.98c0 75.649 61.331 136.944 137.017 136.944zM448.929 370.851c-28.962-28.926-63.325-46.252-187.655-46.252s-157.859 18.776-185.335 46.252c-27.44 27.44-18.196 320.43-18.196 320.43l60.824-144.411 38.241 430.334 110.23-220.278 102.907 220.278 36.393-430.334 60.824 144.411c-0.036 0 10.693-291.468-18.233-320.43z" - ], - "width": 489, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "customers" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 82, - "id": 56, - "prevSize": 32, - "code": 58883, - "name": "customers", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 56 - }, - { - "icon": { - "paths": [ - "M680.975 73.728c-337.523 0-610.976 273.515-611.038 610.976 0.122 37.72 1.039 251.812 1.039 251.812h1219.997c0 0 0.978-239.219 1.039-251.812-0.183-337.523-273.637-610.976-611.038-610.976zM737.708 197.831c31.117 3.607 61.379 10.271 90.418 19.624l-19.93 61.685c-25.004-8.070-51.169-13.939-78.191-16.995l7.703-64.313zM270.091 673.15h-64.864c0-31.423 3.118-62.235 8.803-92.007l63.702 12.349c-5.135 25.799-7.642 52.392-7.642 79.658zM305.855 504.419l-59.178-26.288c12.655-28.489 28-55.449 45.79-80.636l52.942 37.475c-15.284 21.825-28.611 45.056-39.554 69.449zM407.46 365.155l-43.405-48.113c22.925-20.541 47.807-39.187 74.462-54.96l33.318 55.571c-22.987 13.755-44.567 29.65-64.374 47.501zM536.943 217.455c29.039-9.292 59.178-16.017 90.418-19.624l7.581 64.313c-26.838 3.057-53.003 8.926-78.13 16.995l-19.869-61.685zM761.673 801.532l-152.897 27.205-38.881-150.452 395.172-404.22-203.394 527.467zM1019.476 434.971l52.942-37.414c17.79 25.187 33.257 52.148 45.851 80.636l-59.178 26.288c-10.943-24.454-24.209-47.685-39.615-69.51zM1094.916 673.15c0-27.266-2.69-53.859-7.703-79.658l63.702-12.349c5.808 29.834 8.803 60.645 8.803 92.007h-64.802zM646.006 770.659c26.777 17.056 62.174 9.415 79.291-17.24 17.118-26.593 9.292-62.051-17.301-79.108-26.655-17.24-62.051-9.354-79.23 17.362-17.118 26.349-9.476 61.99 17.24 78.986z" - ], - "width": 1376, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "dashboard" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 81, - "id": 57, - "prevSize": 32, - "code": 58884, - "name": "dashboard", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 57 - }, - { - "icon": { - "paths": [ - "M24.097 113.465h972.827v111.922l-410.504 412.792v238.366l-171.447 87.505v-325.871l-390.875-415.877v-108.837z" - ], - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "filter" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 80, - "id": 58, - "prevSize": 32, - "code": 58885, - "name": "filter", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 58 - }, - { - "icon": { - "paths": [ - "M59.153 534.182l164.053 38.141v-303.902l-164.053 38.141v227.621zM1122.198 59.153l-837.712 194.959v335.978l140.328 376.832 151.712-57.45-104.049-279.113 649.668 151.18v-722.385z" - ], - "width": 1170, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "promotions" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 79, - "id": 59, - "prevSize": 32, - "code": 58889, - "name": "promotions", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 59 - }, - { - "icon": { - "paths": [ - "M736.707 981.234h207.134v-322.703h-207.134v322.703zM399.646 981.234h207.134v-946.793h-207.134v946.793zM62.673 981.19h207.134v-634.704h-207.134v634.704z" - ], - "width": 991, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "reports" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 78, - "id": 60, - "prevSize": 32, - "code": 58890, - "name": "reports", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 60 - }, - { - "icon": { - "paths": [ - "M426.502 612.517c-15.866-13.512-42.796-25.753-80.79-36.723v198.774c11.535-1.459 23.729-4.331 36.299-8.851 12.618-4.426 23.87-10.829 33.804-19.068 9.981-8.427 18.173-18.55 24.529-30.649 6.638-12.006 9.651-26.365 9.651-42.89 0.047-26.836-7.721-47.222-23.493-60.593zM576.736 736.856c-7.109 23.117-19.774 45.762-38.135 67.749-18.503 22.175-43.079 41.855-74.010 58.992-30.885 17.373-70.432 27.683-118.878 31.12v88.088h-57.014v-88.088c-72.080-5.603-128.483-29.237-169.113-71.374-40.536-42.090-63.935-104.095-70.432-185.544h136.251c-0.753 39.359 8.992 70.479 28.86 93.266 20.15 22.74 44.774 37.335 74.434 43.455v-216.523c-3.060-1.318-7.486-2.919-12.994-4.567-5.508-1.789-11.393-3.343-17.938-4.708-23.776-6.827-47.175-15.019-70.291-24.294-23.493-9.369-44.114-21.704-62.523-37.335-18.456-15.584-33.098-34.84-43.879-57.956-11.111-23.211-16.478-51.977-16.478-86.487 0-35.31 6.168-66.336 18.785-93.313 12.665-26.836 29.143-49.529 49.858-67.702 20.621-18.314 44.303-32.58 71.468-42.419 27.071-10.122 55.037-16.149 83.992-18.314v-79.66h57.014v79.66c29.143 3.531 56.308 10.169 81.638 20.292 25.423 10.028 47.787 23.729 67.137 41.478 19.585 17.514 35.357 39.453 47.457 65.771 12.288 26.13 19.35 57.109 21.28 93.172h-137.287c-0.518-27.636-8.616-51.082-23.917-70.432-15.725-19.303-34.275-29.002-56.308-29.002v183.331c7.862 2.072 15.631 4.143 23.729 6.12 8.098 2.072 16.525 4.567 25.565 7.297 47.645 13.983 84.415 31.12 110.168 51.318 25.8 20.292 44.726 41.666 56.92 63.653 12.335 22.175 19.633 44.256 21.704 66.336 2.448 22.081 3.531 41.713 3.531 59.039 0.047 15.207-3.531 34.416-10.593 57.579zM228.905 263.415c-8.38 7.156-15.113 16.196-19.962 26.883-4.802 10.781-7.062 23.352-7.062 37.759 0 22.834 6.733 40.536 20.103 52.824 13.653 12.618 35.734 22.552 66.713 30.131v-168.831c-10.829 0-21.516 1.695-31.826 5.226-10.216 3.437-19.633 8.851-27.966 16.007z" - ], - "width": 659, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "sales" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 77, - "id": 61, - "prevSize": 32, - "code": 58891, - "name": "sales", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 61 - }, - { - "icon": { - "paths": [ - "M555.139 21.642c-218.775-71.601-457.062 40.29-532.231 250.028-75.227 209.681 41.211 437.665 259.928 509.208 218.717 71.601 457.004-40.348 532.231-250.028s-41.211-437.665-259.928-509.208zM320.076 677.045c-158.915-52.089-243.467-217.681-188.903-369.978 54.679-152.296 227.754-233.625 386.669-181.593s243.409 217.624 188.788 369.92c-54.622 152.296-227.696 233.567-386.554 181.65z", - "M638.482 685.794l358.927 349.602 24.807-69.241 24.865-69.241-310.348-302.29z" - ], - "width": 1109, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "search" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - }, - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 76, - "id": 62, - "prevSize": 32, - "code": 58892, - "name": "search", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 62 - }, - { - "icon": { - "paths": [ - "M1098.281 85.45c19.777-3.723 34.901-21.232 34.901-42.347-0.058-23.791-19.196-43.103-42.812-43.103h-900.508c-23.675 0-42.754 19.312-42.754 43.103 0 21.057 15.007 38.566 34.843 42.347l-181.951 354.421v68.988c0 30.946 32.516 56.016 72.594 56.016 13.437 0 26.001-2.908 36.821-7.795v466.919h1061.286v-466.919c10.878 4.944 23.326 7.795 36.879 7.795 40.078 0 72.594-25.071 72.594-56.016v-68.988l-181.893-354.421zM214.758 564.875c-38.217 0-69.221-25.071-69.221-56.016v-6.457h-0.349v-62.531l137.162-353.665h109.648l-107.961 353.665v68.988c0 0 0 0 0 0 0 30.946-31.004 56.016-69.279 56.016zM498.447 564.875c-38.217 0-69.221-25.071-69.221-56.016v-68.988l57.354-353.665h109.241l-28.095 353.665v68.93c-0.058 31.004-31.004 56.075-69.279 56.075zM782.077 564.875c-38.217 0-69.162-25.071-69.162-56.016v-68.988l-28.154-353.665h108.892l57.296 353.665v68.988c0 0.931 0.175 1.92 0.233 2.792-1.803 29.666-32.051 53.224-69.104 53.224zM1134.637 508.859c0 30.946-31.004 56.016-69.221 56.016s-69.162-25.071-69.162-56.016v-68.988l-108.019-353.665h109.59l137.22 353.665v62.473h-0.349v6.515h-0.058z" - ], - "width": 1280, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "stores" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 75, - "id": 63, - "prevSize": 32, - "code": 58893, - "name": "stores", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 63 - }, - { - "icon": { - "paths": [ - "M944.97 329.042c-97.861 0-177.522 79.581-177.522 177.443 0 97.94 79.66 177.679 177.522 177.679 98.019 0 177.679-79.739 177.679-177.679 0-97.861-79.66-177.443-177.679-177.443zM944.97-0c-470.712 0-944.97 512-944.97 512s474.258 512 944.97 512c470.949 0 945.128-512 945.128-512s-474.179-512-945.128-512zM944.97 868.856c-200.057 0-362.292-162.078-362.292-362.45 0-200.057 162.236-362.292 362.292-362.292 200.214 0 362.45 162.236 362.45 362.292 0 200.451-162.236 362.45-362.45 362.45z" - ], - "width": 1890, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "views" - ], - "grid": 0 - }, - "attrs": [ - { - "opacity": 1, - "visibility": false - } - ], - "properties": { - "order": 73, - "id": 64, - "prevSize": 32, - "code": 58895, - "name": "views", - "ligatures": "" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 64 - }, - { - "icon": { - "paths": [ - "M1042.226 299.849h-598.393v-299.849l-443.833 384.316 443.833 384.403v-299.859h598.393c106.478 0 192.801 86.318 192.801 192.801s-86.318 192.796-192.801 192.796v0.483l-452.707 0.005c-46.695 0.005-84.53 37.845-84.53 84.535 0 46.68 37.84 84.525 84.535 84.525 0.377 0 0.744-0.053 1.121-0.058h451.581c199.964 0 362.044-162.085 362.044-362.039 0-199.964-162.080-362.059-362.044-362.059z" - ], - "width": 1404, - "attrs": [], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "revert" - ], - "grid": 0 - }, - "attrs": [], - "properties": { - "order": 129, - "id": 65, - "prevSize": 32, - "code": 58946, - "name": "revert" - }, - "setIdx": 0, - "setId": 7, - "iconIdx": 65 - }, - { - "icon": { - "paths": [ - "M1023.959 505.088c-3.717-282.665-236.121-508.842-518.817-505.040-282.689 3.772-508.866 236.091-505.094 518.868 3.772 282.58 236.121 508.842 518.813 505.040 282.689-3.772 508.866-236.067 505.098-518.868zM580.086 904.359h-136.149v-136.163h136.149v136.163zM597.168 293.742l-44.103 388.928h-83.113l-43.099-388.928v-171.575h170.318v171.575z" - ], - "attrs": [ - { - "fill": "rgb(100, 97, 96)" - } - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "alert-round" - ], - "grid": 32 - }, - "attrs": [ - { - "fill": "rgb(100, 97, 96)" - } - ], - "properties": { - "order": 132, - "id": 0, - "name": "alert-round", - "prevSize": 32, - "code": 58952 - }, - "setIdx": 1, - "setId": 6, - "iconIdx": 0 - }, - { - "icon": { - "paths": [ - "M793.271 222.6l-192.695-83.055v80.482c-2.517 31.926-83.182 57.618-182.582 57.618-99.309 0-180.126-25.692-182.398-57.618h-0.318l-0.465-80.482-197.709 83.055 381.218 167.697 374.95-167.697zM265.959 118.114l-1.104 0.428c32.596 16.331 89.086 27.124 153.551 27.124 64.726 0 121.621-10.94 153.996-27.355l-1.168-0.512c18.811-9.3 29.664-20.34 29.664-32.264 0-32.713-81.606-59.114-182.492-59.114-100.759 0-182.806 26.401-182.806 59.114-0.003 12.007 11.295 23.218 30.36 32.579zM418.418 462.436l-418.418-191.009v563.335l418.321 189.238 418.321-189.238v-563.733l-418.224 191.407z" - ], - "width": 883, - "attrs": [ - {} - ], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "module" - ], - "grid": 32 - }, - "attrs": [ - {} - ], - "properties": { - "order": 131, - "id": 1, - "name": "module", - "prevSize": 32, - "code": 58951 - }, - "setIdx": 1, - "setId": 6, - "iconIdx": 1 - }, - { - "icon": { - "paths": [ - "M939.616 148.384c112.512 112.448 112.512 294.816 0 407.264l-350.944 350.976c-12.512 12.544-32.736 12.544-45.248 0-12.576-12.512-12.576-32.704 0-45.248l346.432-346.464c87.488-87.488 87.488-229.248-0.064-316.768-87.36-87.488-229.248-87.488-316.736 0l-462.304 456.864c-62.496 62.464-62.496 163.776 0 226.24 62.496 62.496 163.744 62.496 226.24 0l466.88-461.344c37.44-37.44 37.44-98.336 0-135.776-37.44-37.408-98.304-37.408-135.744 0l-351.008 351.008c-12.512 12.512-32.736 12.512-45.248 0-12.512-12.544-12.512-32.736 0-45.28l350.976-350.976c62.432-62.464 163.744-62.464 226.24 0 62.496 62.496 62.496 163.776 0 226.272l-466.88 461.376c-87.296 87.328-229.408 87.328-316.736 0-87.328-87.328-87.328-229.472 0-316.8l466.88-461.344c112.448-112.512 294.816-112.512 407.264 0z" - ], - "attrs": [], - "isMulticolor": false, - "isMulticolor2": false, - "tags": [ - "clip", - "paperclip", - "attachment" - ], - "grid": 32 - }, - "attrs": [], - "properties": { - "id": 2, - "order": 130, - "prevSize": 32, - "code": 58947, - "name": "clip" - }, - "setIdx": 1, - "setId": 6, - "iconIdx": 2 + "IcoMoonType": "selection", + "icons": [ + { + "icon": { + "paths": [ + "M0 512v512h793.43v-771.052l-42.045-36.62c-23.735-19.666-46.114-39.332-50.183-43.401-4.069-3.391-16.275-14.241-27.126-23.735s-53.574-46.792-94.94-83.412l-75.952-65.78h-503.184v512zM465.886 213.616c0.678 56.286 1.356 105.791 2.034 109.86 0 6.781 25.77 8.816 107.147 8.816h107.147v287.534c-0.678 252.27-1.356 288.212-10.85 290.246-5.425 1.356-133.595 2.034-284.821 2.034l-274.649-0.678-1.356-392.646c-0.678-216.328-0.678-396.715 0.678-400.106 1.356-4.069 67.136-6.781 177.674-6.781h175.64l1.356 101.722z" + ], + "attrs": [ + {} + ], + "width": 793, + "isMulticolor": false, + "isMulticolor2": false, + "grid": 32, + "tags": [ + "document" + ] + }, + "attrs": [ + {} + ], + "properties": { + "order": 133, + "id": 0, + "name": "document", + "prevSize": 32, + "code": 58953 + }, + "setIdx": 0, + "setId": 2, + "iconIdx": 0 + }, + { + "icon": { + "paths": [ + "M1023.959 505.088c-3.717-282.665-236.121-508.842-518.817-505.040-282.689 3.772-508.866 236.091-505.094 518.868 3.772 282.58 236.121 508.842 518.813 505.040 282.689-3.772 508.866-236.067 505.098-518.868zM580.086 904.359h-136.149v-136.163h136.149v136.163zM597.168 293.742l-44.103 388.928h-83.113l-43.099-388.928v-171.575h170.318v171.575z" + ], + "attrs": [ + { + "fill": "rgb(100, 97, 96)" + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "alert-round" + ], + "grid": 32 + }, + "attrs": [ + { + "fill": "rgb(100, 97, 96)" } - ], - "height": 1024, - "metadata": { - "name": "icomoon" - }, - "preferences": { - "showGlyphs": true, - "showQuickUse": true, - "showQuickUse2": true, - "showSVGs": true, - "fontPref": { - "prefix": "icon-", - "metadata": { - "fontFamily": "icomoon", - "majorVersion": 1, - "minorVersion": 0 - }, - "metrics": { - "emSize": 1024, - "baseline": 6.25, - "whitespace": 50 - }, - "resetPoint": 58880, - "showVersion": true, - "showSelector": false, - "showMetrics": false, - "showMetadata": false, - "embed": false - }, - "imagePref": { - "prefix": "icon-", - "png": true, - "useClassSelector": true, - "classSelector": ".icon" - }, - "historySize": 100, - "showCodes": true, - "search": "", - "gridSize": 16, - "showLiga": false + ], + "properties": { + "order": 132, + "id": 0, + "name": "alert-round", + "prevSize": 32, + "code": 58952 + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 66 + }, + { + "icon": { + "paths": [ + "M793.271 222.6l-192.695-83.055v80.482c-2.517 31.926-83.182 57.618-182.582 57.618-99.309 0-180.126-25.692-182.398-57.618h-0.318l-0.465-80.482-197.709 83.055 381.218 167.697 374.95-167.697zM265.959 118.114l-1.104 0.428c32.596 16.331 89.086 27.124 153.551 27.124 64.726 0 121.621-10.94 153.996-27.355l-1.168-0.512c18.811-9.3 29.664-20.34 29.664-32.264 0-32.713-81.606-59.114-182.492-59.114-100.759 0-182.806 26.401-182.806 59.114-0.003 12.007 11.295 23.218 30.36 32.579zM418.418 462.436l-418.418-191.009v563.335l418.321 189.238 418.321-189.238v-563.733l-418.224 191.407z" + ], + "width": 883, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "module" + ], + "grid": 32 + }, + "attrs": [ + {} + ], + "properties": { + "order": 131, + "id": 1, + "name": "module", + "prevSize": 32, + "code": 58951 + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 67 + }, + { + "icon": { + "paths": [ + "M939.616 148.384c112.512 112.448 112.512 294.816 0 407.264l-350.944 350.976c-12.512 12.544-32.736 12.544-45.248 0-12.576-12.512-12.576-32.704 0-45.248l346.432-346.464c87.488-87.488 87.488-229.248-0.064-316.768-87.36-87.488-229.248-87.488-316.736 0l-462.304 456.864c-62.496 62.464-62.496 163.776 0 226.24 62.496 62.496 163.744 62.496 226.24 0l466.88-461.344c37.44-37.44 37.44-98.336 0-135.776-37.44-37.408-98.304-37.408-135.744 0l-351.008 351.008c-12.512 12.512-32.736 12.512-45.248 0-12.512-12.544-12.512-32.736 0-45.28l350.976-350.976c62.432-62.464 163.744-62.464 226.24 0 62.496 62.496 62.496 163.776 0 226.272l-466.88 461.376c-87.296 87.328-229.408 87.328-316.736 0-87.328-87.328-87.328-229.472 0-316.8l466.88-461.344c112.448-112.512 294.816-112.512 407.264 0z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "clip", + "paperclip", + "attachment" + ], + "grid": 32 + }, + "attrs": [], + "properties": { + "id": 2, + "order": 130, + "prevSize": 32, + "code": 58947, + "name": "clip" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 68 + }, + { + "icon": { + "paths": [ + "M2041.366 1.102v1021.449h-175.926l-411.263-409.297v-204.59l411.263-407.568h175.926z", + "M1305.997 989.076c0 19.377-15.608 34.924-34.856 34.924h-1236.279c-19.255 0-34.863-15.547-34.863-34.924v-954.275c0-19.248 15.608-34.801 34.863-34.801h1236.279c19.248 0 34.856 15.553 34.856 34.801v954.275z" + ], + "width": 2041, + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "video" + ], + "grid": 0 + }, + "attrs": [], + "properties": { + "order": 127, + "id": 0, + "prevSize": 32, + "code": 58945, + "name": "video" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 0 + }, + { + "icon": { + "paths": [ + "M723.661 889.601c-2.404-10.843-4.034-21.47-5.282-31.583h-277.528c-2.458 20.233-6.917 43.087-14.646 64.305-7.79 21.277-18.796 40.54-33.824 54.15-15.028 13.552-33.689 22.104-59.788 22.158v25.369h494.020v-25.369c-26.142-0.058-44.737-8.61-59.838-22.158-22.44-20.307-35.961-53.91-43.114-86.873zM1126.214 0h-1093.209c-18.22 0-33.005 15.024-33.005 33.596v731.259c0 18.576 14.785 33.623 33.005 33.623h1093.209c18.224 0 33.067-15.051 33.067-33.623v-731.259c0-18.572-14.843-33.596-33.067-33.596zM1079.193 716.922h-999.234v-635.394h999.234v635.394z" + ], + "width": 1159, + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "screen" + ], + "grid": 0 + }, + "attrs": [], + "properties": { + "order": 72, + "id": 1, + "prevSize": 32, + "code": 58944, + "name": "screen" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 1 + }, + { + "icon": { + "paths": [ + "M771.001 776.737c-55.445 0-100.448 44.754-100.448 100.2s44.879 100.324 100.448 100.324 100.448-44.879 100.448-100.324-45.003-100.2-100.448-100.2zM771.001 918.707c-23.123 0-41.77-18.648-41.77-41.771s18.647-41.77 41.77-41.77c23.247 0 41.895 18.648 41.895 41.77s-18.648 41.771-41.895 41.771z", + "M469.532 776.737c-55.445 0-100.449 44.754-100.449 100.2s45.003 100.324 100.449 100.324c55.445 0 100.448-44.879 100.448-100.324s-45.003-100.2-100.448-100.2zM469.532 918.707c-23.123 0-41.771-18.648-41.771-41.771s18.648-41.77 41.771-41.77 41.77 18.648 41.77 41.77-18.648 41.771-41.77 41.771z", + "M823.587 494.412c-130.036 0-238.441-91.622-264.547-213.825h-207.237l-136.749-198.162v-1.865h-207.237v83.541h169.942l78.693 117.729 83.417 412.857h581.183l49.23-243.786c-42.268 27.474-92.616 43.511-146.694 43.511z", + "M1023.862 249.756v-45.376l-55.073-18.026-12.929-31.204 24.863-52.71-31.95-32.074-5.967 2.984-45.5 23.123-31.328-12.929-19.642-54.948h-45.376l-2.114 6.464-15.912 48.608-31.203 12.929-52.835-24.863-32.074 31.95 3.108 5.967 23.247 45.624-13.053 31.328-54.948 19.766v45.376l6.34 2.113 48.732 15.788 12.929 31.204-24.863 52.71 32.074 32.074 6.092-3.108 45.376-22.999 31.328 12.929 19.642 54.824h45.376l2.113-6.464 15.913-48.359 31.203-12.929 52.71 24.988 32.198-32.074-3.108-6.092-23.247-45.624 12.929-31.203 54.948-19.766zM824.582 291.527c-35.057 0-63.65-28.469-63.65-63.526 0-35.182 28.469-63.526 63.65-63.526s63.526 28.469 63.526 63.526c-0.124 35.182-28.469 63.526-63.526 63.526z" + ], + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "cart" + ], + "grid": 0 + }, + "attrs": [], + "properties": { + "order": 71, + "id": 2, + "prevSize": 32, + "code": 58943, + "name": "cart" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 2 + }, + { + "icon": { + "paths": [ + "M0.010 188.484h1023.966v136.509h-1023.966z", + "M0.010 442.47h1023.966v136.506h-1023.966z", + "M0.010 699.017h1023.966v136.513h-1023.966z" + ], + "attrs": [ + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "list-menu" + ], + "grid": 0 + }, + "attrs": [ + {}, + {}, + {} + ], + "properties": { + "order": 61, + "id": 3, + "prevSize": 32, + "code": 58942, + "name": "list-menu" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 3 + }, + { + "icon": { + "paths": [ + "M0.010 0.372h279.074v279.074h-279.074z", + "M372.77 0.372h279.074v279.074h-279.074z", + "M744.892 0.372h279.074v279.074h-279.074z", + "M0.010 372.497h279.074v279.074h-279.074z", + "M372.77 372.497h279.074v279.074h-279.074z", + "M744.892 372.497h279.074v279.074h-279.074z", + "M0.010 744.585h279.074v279.074h-279.074z", + "M372.77 744.585h279.074v279.074h-279.074z", + "M744.892 744.585h279.074v279.074h-279.074z" + ], + "attrs": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "grid" + ], + "grid": 0 + }, + "attrs": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "properties": { + "order": 112, + "id": 4, + "prevSize": 32, + "code": 58941, + "name": "grid" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 4 + }, + { + "icon": { + "paths": [ + "M982.767 231.902h-250.095l-59.255-121.364c0 0-11.827-25.201-42.11-25.201-23.375 0-169.366 0-235.25 0-32.969 0-44.001 25.027-44.001 25.027l-57.484 121.539h-253.406c-22.74 0-41.131 18.459-41.131 41.267v624.333c0 22.743 18.401 41.199 41.131 41.199h941.636c22.74 0 41.199-18.459 41.199-41.199v-624.299c0-22.798-18.456-41.267-41.199-41.267zM512 823.91c-138.793 0-251.597-113.015-251.597-251.931 0-138.912 112.845-251.87 251.597-251.87 138.68 0 251.597 112.981 251.597 251.87 0 138.909-112.913 251.931-251.597 251.931z", + "M512 420.932c-83.255 0-150.972 67.714-150.972 150.972 0 83.197 67.71 150.903 150.972 150.903 83.258 0 150.903-67.714 150.903-150.903 0-83.255-67.652-150.972-150.903-150.972z" + ], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "camera" + ], + "grid": 0 + }, + "attrs": [ + {}, + {} + ], + "properties": { + "order": 121, + "id": 5, + "prevSize": 32, + "code": 58940, + "name": "camera" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 5 + }, + { + "icon": { + "paths": [ + "M904.192 0.027l-307.234 0.116-596.89 596.958 426.906 426.906 596.958-596.958-0.113-305.596-119.603-121.426zM858.679 313.337c-39.997 40.001-104.854 40.001-144.794 0-40.001-40.001-40.001-104.796 0-144.794 39.939-40.001 104.796-40.001 144.794 0 39.997 39.997 39.997 104.793 0 144.794z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "tag" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 111, + "id": 6, + "prevSize": 32, + "code": 58939, + "name": "tag" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 6 + }, + { + "icon": { + "paths": [ + "M1094.391 77.71l-77.71-77.71-423.329 423.347-423.33-423.347-77.71 77.672 423.35 423.368-423.312 423.329 77.672 77.71 423.338-423.338 423.283 423.3 77.671-77.71-423.263-423.281z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "colorPermutations": { + "6868681": [ + { + "f": 0 + } + ] + }, + "tags": [ + "close-mage" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 110, + "id": 7, + "prevSize": 32, + "code": 58927, + "name": "close-mage" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 7 + }, + { + "icon": { + "paths": [ + "M857.675 289.413l-403.18-240.514-402.726 240.514v457.026l403.18 240.515 402.726-240.514v-457.027zM454.857 864.465l-298.427-178.383v-335.966l298.157-178.729 298.428 178.383v335.966l-298.158 178.729z" + ], + "width": 903, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "colorPermutations": { + "6868681": [ + { + "f": 0 + } + ] + }, + "tags": [ + "menu-item" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 109, + "id": 8, + "prevSize": 32, + "code": 58938, + "name": "menu-item" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 8 + }, + { + "icon": { + "paths": [ + "M505.704 40.998c-260.096 3.489-468.158 217.202-464.706 477.336 3.489 259.982 217.202 468.12 477.298 464.631s468.158-217.202 464.706-477.336c-3.413-260.058-217.202-468.12-477.298-464.631zM557.928 197.973c47.863 0 62.009 27.762 62.009 59.544 0 39.671-31.782 76.383-86.016 76.383-45.359 0-66.901-22.831-65.65-60.53 0-31.782 26.624-75.435 89.657-75.435zM435.162 806.381c-32.73 0-56.661-19.873-33.792-107.217l37.547-154.814c6.485-24.841 7.585-34.778 0-34.778-9.785 0-52.262 17.143-77.407 34.057l-16.346-26.776c79.607-66.446 171.16-105.472 210.375-105.472 32.73 0 38.153 38.722 21.807 98.266l-43.008 162.816c-7.585 28.786-4.286 38.722 3.262 38.722 9.785 0 41.984-11.871 73.614-36.75l18.47 24.841c-77.369 77.369-161.792 107.179-194.56 107.179z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "info" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 108, + "id": 9, + "prevSize": 32, + "code": 58906, + "name": "info" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 9 + }, + { + "icon": { + "paths": [ + "M591.986 448.019h-16.005v-192.019c0-105.851-86.13-192.019-192.019-192.019h-128c-105.851 0-192.019 86.13-192.019 192.019v192.019h-16.005c-26.396 0-48.014 21.618-48.014 48.014v479.991c0 26.396 21.618 48.014 48.014 48.014h544.009c26.396 0 48.014-21.618 48.014-48.014v-479.991c0-26.396-21.618-48.014-48.014-48.014zM384 896h-128l27.838-139.188c-16.801-11.529-27.838-30.872-27.838-52.793 0-35.347 28.672-64.019 64.019-64.019s64.019 28.672 64.019 64.019c0 21.921-11.036 41.263-27.838 52.793l27.838 139.188zM448.019 448.019h-256v-192.019c0-35.271 28.71-64.019 64.019-64.019h128c35.271 0 64.019 28.71 64.019 64.019v192.019z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "lock" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 107, + "id": 10, + "prevSize": 32, + "code": 58907, + "name": "lock" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 10 + }, + { + "icon": { + "paths": [ + "M870.4 317.44h-194.56v143.36h153.6v215.040h-634.88v-215.040h215.040v112.64l204.8-184.32-204.8-184.32v112.64h-256c-56.51 0-102.4 45.815-102.4 102.4v296.96c0 56.51 45.89 102.4 102.4 102.4h716.8c56.585 0 102.4-45.89 102.4-102.4v-296.96c0-56.585-45.815-102.4-102.4-102.4z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "loop" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 106, + "id": 11, + "prevSize": 32, + "code": 58908, + "name": "loop" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 11 + }, + { + "icon": { + "paths": [ + "M991.991 384h-351.991v-351.991c0-17.673-14.336-32.009-32.009-32.009h-192.019c-17.673 0-32.009 14.336-32.009 32.009v351.991h-351.991c-17.673 0-32.009 14.336-32.009 32.009v192.019c0 17.673 14.336 32.009 32.009 32.009h351.991v351.991c0 17.673 14.336 32.009 32.009 32.009h192.019c17.673 0 32.009-14.336 32.009-32.009v-351.991h351.991c17.673 0 32.009-14.336 32.009-32.009v-192.019c0-17.673-14.336-32.009-32.009-32.009z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "plus" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 105, + "id": 12, + "prevSize": 32, + "code": 58909, + "name": "plus" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 12 + }, + { + "icon": { + "paths": [ + "M505.704 40.998c-260.096 3.489-468.158 217.126-464.706 477.298 3.489 260.21 217.202 468.158 477.298 464.744 260.134-3.489 468.233-217.202 464.706-477.298-3.489-260.21-217.202-468.233-477.298-464.744zM506.577 102.4c70.163-0.986 136.382 15.853 194.56 46.118l-63.374 105.662c-38.002-18.47-80.631-28.937-125.762-28.937-45.056 0-87.723 10.43-125.687 28.975l-63.336-105.624c54.993-28.672 117.343-45.321 183.599-46.232zM254.255 637.687l-105.586 63.298c-28.672-54.955-45.321-117.305-46.194-183.486-0.986-70.201 15.853-136.457 46.118-194.56l105.624 63.45c-18.546 37.926-28.975 80.555-28.975 125.649 0 45.056 10.43 87.723 28.975 125.687zM517.461 921.562c-70.163 0.986-136.457-15.853-194.56-46.118l63.374-105.662c38.002 18.546 80.631 28.975 125.687 28.975 45.094 0 87.761-10.392 125.687-28.937l63.336 105.586c-54.993 28.634-117.305 45.246-183.561 46.194zM512 737.242c-124.397 0-225.242-100.883-225.242-225.242 0-124.397 100.883-225.28 225.242-225.28 124.473 0 225.28 100.883 225.28 225.28s-100.807 225.242-225.28 225.242zM769.745 637.687c18.546-38.002 28.975-80.631 28.975-125.687 0-45.094-10.43-87.723-28.975-125.687l105.586-63.374c28.672 54.993 45.359 117.305 46.232 183.561 0.91 70.201-15.929 136.457-46.194 194.56l-105.624-63.336z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "recover" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 104, + "id": 13, + "prevSize": 32, + "code": 58910, + "name": "recover" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 13 + }, + { + "icon": { + "paths": [ + "M906.126 135.813v0c-91.174-75.89-202.487-113.171-312.548-113.057-127.014-0.038-253.611 49.683-348.16 145.636l-95.004-79.265-1.593 305.342 300.184-56.282-99.442-82.944c67.546-64.247 155.269-97.204 244.015-97.28 79.948 0.038 159.782 26.7 226.114 81.806 84.347 70.125 127.659 170.629 127.772 272.46-0.038 14.715-0.948 29.431-2.769 44.070l137.519-26.283c0.19-5.954 0.303-11.871 0.303-17.787 0.152-140.098-60.151-279.78-176.431-376.415zM839.035 766.976c-67.736 65.498-156.255 99.025-245.912 99.1-79.986-0.038-159.82-26.738-226.114-81.806-84.347-70.125-127.697-170.629-127.772-272.498 0-16.839 1.252-33.716 3.679-50.366l-138.164 25.941c-0.379 8.116-0.683 16.346-0.683 24.462-0.114 140.174 60.226 279.817 176.545 376.491 91.136 75.852 202.411 113.057 312.51 112.981h0.341c127.924 0 255.241-50.441 349.943-147.759l90.795 75.207 0.569-305.38-299.956 57.344 104.183 86.281z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "refresh" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 113, + "id": 14, + "prevSize": 32, + "code": 58911, + "name": "refresh" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 14 + }, + { + "icon": { + "paths": [ + "M593.351 21.732c-270.753 0-490.268 219.477-490.268 490.231s219.515 490.268 490.268 490.268 490.231-219.515 490.231-490.268c0-270.753-219.477-490.231-490.231-490.231zM828.947 683.653l-72.363 72.363-162.095-162.133-164.902 164.902-73.121-73.121 164.902-164.902-161.678-161.678 72.363-72.325 161.602 161.678 165.774-165.736 73.121 73.083-165.774 165.736 162.171 162.133z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "remove-small" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 114, + "id": 15, + "prevSize": 32, + "code": 58912, + "name": "remove-small" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 15 + }, + { + "icon": { + "paths": [ + "M254.976 675.84v-267.264h103.424l-179.2-203.776-179.2 203.776h103.424v308.224c0 56.51 45.815 102.4 102.4 102.4h459.776l-131.186-143.36h-279.438zM920.538 615.424v-308.224c0-56.51-45.89-102.4-102.4-102.4h-459.738l131.11 143.36h279.514v267.264h-103.424l179.2 203.776 179.2-203.776h-103.462z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "retweet" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 117, + "id": 16, + "prevSize": 32, + "code": 58913, + "name": "retweet" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 16 + }, + { + "icon": { + "paths": [ + "M768 64.019h-128c-105.851 0-192.019 86.13-192.019 192.019v192.019h-400.005c-26.396 0-48.014 21.618-48.014 48.014v479.991c0 26.396 21.618 48.014 48.014 48.014h544.009c26.396 0 48.014-21.618 48.014-48.014v-479.991c0-26.396-21.618-48.014-48.014-48.014h-16.005v-192.019c0-35.271 28.71-64.019 64.019-64.019h128c35.271 0 64.019 28.71 64.019 64.019v192.019h128v-192.019c0-105.851-86.13-192.019-192.019-192.019zM384 896h-128l27.838-139.188c-16.801-11.529-27.838-30.872-27.838-52.793 0-35.347 28.672-64.019 64.019-64.019s64.019 28.672 64.019 64.019c0 21.921-11.036 41.263-27.838 52.793l27.838 139.188z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "unlocked" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 36, + "id": 17, + "prevSize": 32, + "code": 58914, + "name": "unlocked" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 17 + }, + { + "icon": { + "paths": [ + "M593.351 0l-593.351 1023.962h1186.74l-593.351-1023.962zM653.236 899.451h-125.421v-121.211h125.421v121.211zM622.175 728.329h-62.502l-34.816-288.313v-156.748h131.3v156.748l-33.982 288.313z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "warning" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 37, + "id": 18, + "prevSize": 32, + "code": 58915, + "name": "warning" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 18 + }, + { + "icon": { + "paths": [ + "M0 512l512 512v-320.019h512v-384h-512v-320.019z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "arrow-left" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 38, + "id": 19, + "prevSize": 32, + "code": 58916, + "name": "arrow-left" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 19 + }, + { + "icon": { + "paths": [ + "M1024 512l-512-512v320.019h-512v384h512v320.019z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "arrow-right" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 39, + "id": 20, + "prevSize": 32, + "code": 58917, + "name": "arrow-right" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 20 + }, + { + "icon": { + "paths": [ + "M402.735 146.735l-320.019 320.019c-24.993 24.993-24.993 65.498 0 90.491l320.019 320.019c24.993 24.993 65.498 24.993 90.491 0s24.993-65.498 0-90.491l-210.754-210.754h613.49c35.347 0 64.019-28.634 64.019-64.019s-28.672-64.019-64.019-64.019h-613.49l210.754-210.754c12.478-12.478 18.735-28.862 18.735-45.246s-6.258-32.768-18.735-45.246c-24.993-24.993-65.498-24.993-90.491 0z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "back-arrow" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 103, + "id": 21, + "prevSize": 32, + "code": 58918, + "name": "back-arrow" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 21 + }, + { + "icon": { + "paths": [ + "M507.259 578.522h-102.059v101.717h102.059v-101.717zM650.885 714.714h-101.945v101.717h101.945v-101.717zM507.259 714.714h-102.059v101.717h102.059v-101.717zM507.259 442.33h-102.059v101.679h102.059v-101.679zM843.131 244.091c23.4 0 42.287-18.887 42.287-42.174v-145.408c0-23.324-18.887-42.174-42.287-42.174s-42.325 18.849-42.325 42.174v145.408c0.038 23.324 18.925 42.174 42.325 42.174zM343.419 244.091c23.362 0 42.249-18.887 42.249-42.174v-145.408c0-23.324-18.887-42.174-42.249-42.174-23.4 0-42.325 18.849-42.325 42.174v145.408c0 23.324 18.925 42.174 42.325 42.174zM363.444 578.522h-102.059v101.717h102.059v-101.717zM363.444 714.714h-102.059v101.717h102.059v-101.717zM650.885 578.522h-101.945v101.717h101.945v-101.717zM938.325 578.522h-102.059v101.717h102.059v-101.717zM938.325 442.33h-102.059v101.679h102.059v-101.679zM899.337 84.385v46.914c17.598 15.474 28.71 38.153 28.71 63.412 0 46.801-37.964 84.764-84.916 84.764s-84.954-37.964-84.954-84.764c0-25.259 11.15-47.938 28.71-63.412v-46.914h-387.262v46.914c17.56 15.474 28.71 38.153 28.71 63.412 0 46.801-38.002 84.764-84.916 84.764s-84.954-37.964-84.954-84.764c0-25.259 11.15-47.938 28.71-63.412v-46.914h-192.322v925.279h997.035v-925.279h-192.512zM999.234 915.304h-809.832v-589.938h809.832v589.938zM650.885 442.33h-101.945v101.679h101.945v-101.679zM794.624 442.33h-101.983v101.679h101.983v-101.679zM794.624 714.714h-101.983v101.717h101.983v-101.717zM794.624 578.522h-101.983v101.717h101.983v-101.717z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "calendar" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 102, + "id": 22, + "prevSize": 32, + "code": 58919, + "name": "calendar" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 22 + }, + { + "icon": { + "paths": [ + "M132.21 286.758c-13.881-13.729-36.295-13.729-50.138 0-13.805 13.653-13.805 35.878 0 49.607l404.897 400.877c13.881 13.729 36.257 13.729 50.138 0l404.897-400.877c13.805-13.729 13.881-35.878 0-49.607s-36.371-13.729-50.138-0.038l-379.866 365.606-379.79-365.568z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "caret-down" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 101, + "id": 23, + "prevSize": 32, + "code": 58920, + "name": "caret-down" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 23 + }, + { + "icon": { + "paths": [ + "M737.242 891.79c13.729 13.881 13.729 36.257 0 50.138s-35.878 13.881-49.607 0l-400.877-404.821c-13.729-13.881-13.729-36.295 0-50.138l400.877-404.897c13.729-13.881 35.878-13.881 49.607 0s13.729 36.257 0 50.138l-365.568 379.79 365.568 379.79z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "caret-left" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 100, + "id": 24, + "prevSize": 32, + "code": 58921, + "name": "caret-left" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 24 + }, + { + "icon": { + "paths": [ + "M286.72 891.79c-13.729 13.881-13.729 36.257 0 50.138s35.878 13.881 49.607 0l400.877-404.821c13.729-13.881 13.729-36.295 0-50.138l-400.915-404.897c-13.729-13.881-35.878-13.881-49.607 0s-13.729 36.257 0 50.138l365.568 379.79-365.568 379.79z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "caret-right" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 99, + "id": 25, + "prevSize": 32, + "code": 58922, + "name": "caret-right" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 25 + }, + { + "icon": { + "paths": [ + "M891.79 737.242c13.881 13.729 36.295 13.729 50.138 0 13.881-13.729 13.881-35.878 0-49.607l-404.897-400.877c-13.805-13.729-36.257-13.729-50.062 0l-404.897 400.877c-13.805 13.729-13.881 35.878 0 49.607s36.257 13.729 50.138 0l379.79-365.606 379.79 365.606z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "caret-up" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 98, + "id": 26, + "prevSize": 32, + "code": 58923, + "name": "caret-up" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 26 + }, + { + "icon": { + "paths": [ + "M574.767 92.16c-227.593 0-412.672 182.386-418.247 409.335h-125.8l188.378 209.92 188.302-209.92h-146.242c5.537-168.998 143.777-304.393 313.609-304.393 173.397 0 313.913 140.971 313.913 314.899s-140.478 314.861-313.913 314.861c-69.48 0-133.689-22.718-185.685-61.099l-71.983 76.99c70.997 55.751 160.465 89.050 257.707 89.050 231.159 0 418.551-187.961 418.551-419.84-0.038-231.879-187.43-419.84-418.551-419.84z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "ccw" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 97, + "id": 27, + "prevSize": 32, + "code": 58924, + "name": "ccw" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 27 + }, + { + "icon": { + "paths": [ + "M996.617 126.786l-513.555 513.555-256.796-256.834-128.379 128.417 385.214 385.252 641.896-642.010z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "check-mage" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 96, + "id": 28, + "prevSize": 32, + "code": 58925, + "name": "check-mage" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 28 + }, + { + "icon": { + "paths": [ + "M512 40.96c-260.134 0-471.040 210.944-471.040 471.040 0 260.134 210.906 471.040 471.040 471.040s471.040-210.906 471.040-471.040c0-260.134-210.906-471.040-471.040-471.040zM512 880.64c-203.624 0-368.64-165.054-368.64-368.64s165.016-368.64 368.64-368.64 368.64 165.054 368.64 368.64-165.016 368.64-368.64 368.64zM547.84 245.76h-71.68v281.069l174.345 174.345 50.669-50.707-153.335-153.335z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "clock" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 95, + "id": 29, + "prevSize": 32, + "code": 58926, + "name": "clock" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 29 + }, + { + "icon": { + "paths": [ + "M337.541 1021.004h513.024l64.512-645.916h-639.128l61.592 645.916zM737.394 154.169v-116.508c0-19.191-15.398-34.702-34.361-34.702h-217.847c-19.001 0-34.361 15.55-34.361 34.702v114.574c-73.576 8.382-150.149 24.614-226.494 52.338v106.989h738.001v-109.833c0 0-90.074-31.403-224.977-47.559zM668.937 147.759c-47.749-3.224-99.252-4.096-153.297-0.986v-61.44c0-9.519 7.623-17.332 17.143-17.332h118.936c9.519 0 17.218 7.813 17.218 17.332v62.426z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "delete" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 94, + "id": 30, + "prevSize": 32, + "code": 58928, + "name": "delete" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 30 + }, + { + "icon": { + "paths": [ + "M928.503 26.889l-111.502 112.109 156.065 156.9 111.502-112.071-156.065-156.937zM215.002 744.41l156.065 156.9 535.211-538.093-156.065-156.9-535.211 538.093zM103.917 1007.161l188.985-49.873-139.302-140.098-49.683 190.009z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "edit" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 115, + "id": 31, + "prevSize": 32, + "code": 58929, + "name": "edit" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 31 + }, + { + "icon": { + "paths": [ + "M1014.67 822.651c0 0 0 0 0 0l-310.651-310.651 310.651-310.651c0 0 0 0 0 0 3.337-3.337 5.765-7.244 7.32-11.416 4.248-11.378 1.82-24.69-7.32-33.83l-146.735-146.735c-9.14-9.14-22.452-11.567-33.83-7.32-4.172 1.555-8.078 3.982-11.416 7.32 0 0 0 0 0 0l-310.651 310.651-310.651-310.651c0 0 0 0 0 0-3.337-3.337-7.244-5.765-11.416-7.32-11.378-4.248-24.69-1.82-33.83 7.32l-146.735 146.735c-9.14 9.14-11.567 22.452-7.32 33.83 1.555 4.172 3.982 8.078 7.32 11.416 0 0 0 0 0 0l310.651 310.651-310.651 310.651c0 0 0 0 0 0-3.337 3.337-5.765 7.244-7.32 11.416-4.248 11.378-1.82 24.69 7.32 33.83l146.735 146.735c9.14 9.14 22.452 11.567 33.83 7.32 4.172-1.555 8.078-3.982 11.416-7.32 0 0 0 0 0 0l310.651-310.651 310.651 310.651c0 0 0 0 0 0 3.337 3.337 7.244 5.765 11.416 7.32 11.378 4.248 24.69 1.82 33.83-7.32l146.735-146.735c9.14-9.14 11.567-22.452 7.32-33.83-1.555-4.172-3.982-8.078-7.32-11.416z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "error" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 122, + "id": 32, + "prevSize": 32, + "code": 58930, + "name": "error" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 32 + }, + { + "icon": { + "paths": [ + "M593.351 22.566c-270.336 0-489.434 219.098-489.434 489.358s219.098 489.434 489.434 489.434 489.434-219.136 489.434-489.434-219.136-489.358-489.434-489.358zM635.752 826.596c-11.985 11.719-26.396 17.636-43.16 17.636-8.154 0-15.967-1.517-23.4-4.589-7.358-3.034-13.843-7.168-19.456-12.174-5.613-5.158-10.126-11.226-13.388-18.356-3.337-7.13-4.968-14.753-4.968-22.945 0-16.308 5.992-30.303 17.977-42.060 11.947-11.681 26.396-17.598 43.198-17.598 16.308 0 30.606 5.689 42.78 16.801 12.25 11.188 18.318 24.993 18.318 41.339-0.038 16.384-5.992 30.303-17.939 41.984zM778.923 382.673c-3.982 13.767-9.747 26.396-17.18 37.774-7.471 11.454-16.498 22.49-27.079 33.071s-22.49 21.618-35.65 33.033c-11.454 9.785-20.783 18.318-27.913 25.79-7.168 7.396-12.895 14.867-17.218 22.338-4.286 7.433-7.282 15.398-9.026 24.007-1.707 8.609-2.617 49.721-2.617 62.35v22.338h-101.376v-32.616c0-13.729 0.986-56.661 3.034-67.584s5.158-21.125 9.481-30.872 10.012-19.228 17.18-28.369c7.168-9.14 16.232-18.887 27.079-29.203l38.647-36.902c10.847-9.747 20.177-20.632 27.951-32.616 7.737-12.060 11.529-26.7 11.529-43.88 0-22.3-6.978-41.036-21.011-56.206-14.071-15.17-33.944-22.793-59.695-22.793-13.16 0-25.069 2.389-35.65 7.282-10.619 4.817-19.797 11.454-27.496 19.759-7.737 8.344-13.577 17.901-17.598 28.786-3.982 10.847-6.334 21.997-6.865 33.527l-105.624-9.444c3.413-27.496 10.733-51.959 21.921-73.463 11.112-21.466 25.562-39.595 43.311-54.575 17.711-14.829 38.078-26.169 61.023-33.944 22.869-7.699 47.521-11.605 73.842-11.605 24.614 0 47.976 3.603 70.049 10.771 21.959 7.168 41.491 17.711 58.406 31.782 16.839 14.033 30.227 31.365 39.936 51.959 9.709 20.632 14.564 44.411 14.564 71.263 0 18.356-2.010 34.475-5.992 48.166z" + ], + "width": 1176, + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "help" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 124, + "id": 33, + "prevSize": 32, + "code": 58931, + "name": "help" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 33 + }, + { + "icon": { + "paths": [ + "M574.805 92.16c-227.631 0-412.71 182.386-418.247 409.335h-125.838l188.378 209.958 188.302-209.958h-146.242c5.537-168.998 143.777-304.393 313.647-304.393 173.359 0 313.875 140.971 313.875 314.899s-140.478 314.861-313.875 314.861c-69.518 0-133.727-22.718-185.761-61.099l-71.983 76.99c71.073 55.751 160.503 89.050 257.745 89.050 231.121 0 418.513-187.961 418.513-419.84-0.038-231.879-187.43-419.84-418.513-419.84zM537.6 286.72v240.109l153.865 153.865 50.669-50.669-132.855-132.855v-210.413h-71.68z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "history" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 45, + "id": 34, + "prevSize": 32, + "code": 58932, + "name": "history" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 34 + }, + { + "icon": { + "paths": [ + "M510.413 0c-281.907 0-510.413 228.582-510.413 510.413 0 281.933 228.506 510.464 510.413 510.464s510.387-228.557 510.387-510.464c0-281.83-228.48-510.413-510.387-510.413zM865.843 510.413c0 69.99-20.506 135.27-55.578 190.285l-490.163-490.163c55.091-35.021 120.32-55.475 190.31-55.475 195.942 0 355.43 159.411 355.43 355.354zM154.957 510.413c0-69.939 20.506-135.245 55.578-190.31l490.189 490.189c-55.066 35.072-120.371 55.501-190.31 55.501-195.942 0.026-355.456-159.437-355.456-355.379z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "not-installed" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 58, + "id": 35, + "prevSize": 32, + "code": 58936, + "name": "not-installed" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 35 + }, + { + "icon": { + "paths": [ + "M511.77 0c-282.778 0-512.102 229.222-512.102 512.179 0 282.829 229.325 512.102 512.102 512.102 282.931 0.026 512.23-229.248 512.23-512.102 0-282.957-229.299-512.179-512.23-512.179zM143.718 419.968h736.205v184.269h-736.205v-184.269z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "disabled" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 57, + "id": 36, + "prevSize": 32, + "code": 58937, + "name": "disabled" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 36 + }, + { + "icon": { + "paths": [ + "M505.139 0.085c-282.658 3.775-508.826 236.066-505.071 518.827 3.772 282.556 236.1 508.826 518.793 505.003 282.658-3.768 508.826-236.066 505.071-518.827-3.717-282.658-236.1-508.826-518.793-505.003z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "dot" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 56, + "id": 37, + "prevSize": 32, + "code": 58935, + "name": "dot" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 37 + }, + { + "icon": { + "paths": [ + "M383.462 577.51h255.693v-213.043h127.795l-255.642-255.667-255.642 255.667h127.795z", + "M852.173 577.51v170.394h-681.754v-170.394h-170.419v340.89h1022.618v-340.89z" + ], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "export" + ], + "grid": 0 + }, + "attrs": [ + {}, + {} + ], + "properties": { + "order": 93, + "id": 38, + "prevSize": 32, + "code": 58933, + "name": "export" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 38 + }, + { + "icon": { + "paths": [ + "M639.155 108.8h-255.693v213.043h-127.795l255.667 255.667 255.616-255.667h-127.795z", + "M852.173 577.51v170.394h-681.754v-170.394h-170.419v340.89h1022.618v-340.89z" + ], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "import" + ], + "grid": 0 + }, + "attrs": [ + {}, + {} + ], + "properties": { + "order": 92, + "id": 39, + "prevSize": 32, + "code": 58934, + "name": "import" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 39 + }, + { + "icon": { + "paths": [ + "M259.2 0h214.323v214.323h-214.323v-214.323z", + "M259.2 269.875h214.323v214.349h-214.323v-214.349z", + "M259.2 539.776h214.323v214.349h-214.323v-214.349z", + "M259.2 809.651h214.323v214.349h-214.323v-214.349z", + "M549.325 0h214.323v214.323h-214.323v-214.323z", + "M549.325 269.875h214.323v214.349h-214.323v-214.349z", + "M549.325 539.776h214.323v214.349h-214.323v-214.349z", + "M549.325 809.651h214.323v214.349h-214.323v-214.349z" + ], + "attrs": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "gripper" + ], + "grid": 0 + }, + "attrs": [ + {}, + {}, + {}, + {}, + {}, + {}, + {}, + {} + ], + "properties": { + "order": 91, + "id": 40, + "prevSize": 32, + "code": 58903, + "name": "gripper" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 40 + }, + { + "icon": { + "paths": [ + "M860.058 185.062v272l-430.029-269.158-1.894 253.491-424.371-249.754-3.763 647.834 426.24-241.28-5.606 239.437 439.424-252.16v259.635h163.942v-660.045z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "forward" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 90, + "id": 41, + "prevSize": 32, + "code": 58904, + "name": "forward" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 41 + }, + { + "icon": { + "paths": [ + "M163.942 845.107v-271.974l430.029 269.133 1.894-253.491 424.397 249.754 3.738-647.834-426.24 241.28 5.606-239.437-439.424 252.16v-259.635h-163.942v660.045z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "backward" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 89, + "id": 42, + "prevSize": 32, + "code": 58905, + "name": "backward", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 42 + }, + { + "icon": { + "paths": [ + "M512.794 0c-283.187 0-512.794 229.581-512.794 512.794 0 283.187 229.606 512.794 512.794 512.794s512.794-229.632 512.794-512.794c0-283.213-229.581-512.794-512.794-512.794zM512.794 971.213c-253.158 0-458.394-205.261-458.394-458.368 0-253.158 205.261-458.394 458.394-458.394 253.184 0 458.394 205.235 458.394 458.394 0.026 253.107-205.21 458.368-458.394 458.368z", + "M760.013 625.613l30.387-38.4-265.6-206.413-20.787-1.613-259.226 208.026 28.826 39.987 236.8-177.613z" + ], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "expand-close" + ], + "grid": 0 + }, + "attrs": [ + {}, + {} + ], + "properties": { + "order": 88, + "id": 43, + "prevSize": 32, + "code": 58901, + "name": "expand-close" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 43 + }, + { + "icon": { + "paths": [ + "M512.794 0c-283.187 0-512.794 229.581-512.794 512.794 0 283.187 229.606 512.794 512.794 512.794s512.794-229.606 512.794-512.794c0-283.213-229.581-512.794-512.794-512.794zM512.794 971.213c-253.158 0-458.394-205.261-458.394-458.394 0-253.158 205.261-458.394 458.394-458.394 253.184 0 458.394 205.235 458.394 458.394 0.026 253.133-205.21 458.394-458.394 458.394z", + "M265.6 454.4l-30.387 38.4 265.574 206.387 20.813 1.613 259.2-208-28.8-39.987-236.8 177.587z" + ], + "attrs": [ + {}, + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "expand-open" + ], + "grid": 0 + }, + "attrs": [ + {}, + {} + ], + "properties": { + "order": 87, + "id": 44, + "prevSize": 32, + "code": 58902, + "name": "expand-open" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 44 + }, + { + "icon": { + "paths": [ + "M1020.032 565.555v-116.045l-16.41-5.376-124.237-40.525-33.152-80.102 63.718-134.784-82.048-82.125-15.411 7.808-116.531 59.213-80.077-33.178-50.278-140.442h-116.096l-45.875 140.698-80 33.126-134.963-63.744-82.022 82.074 7.834 15.334 59.162 116.608-33.126 80.026-140.518 50.253v116.147l16.435 5.325 124.288 40.576 33.075 80-63.693 134.886 82.048 82.099 131.942-66.97 80.026 33.152 50.304 140.39h116.096l5.35-16.41 40.55-124.237 80.077-33.178 134.886 63.718 82.074-82.074-7.834-15.386-59.213-116.582 33.203-80.026 140.416-50.253zM510.003 672.589c-89.754 0-162.509-72.832-162.509-162.611 0-89.754 72.755-162.483 162.509-162.483 89.83 0 162.509 72.73 162.509 162.483 0.026 89.805-72.653 162.611-162.509 162.611z" + ], + "attrs": [ + { + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "system-config" + ], + "grid": 0 + }, + "attrs": [ + { + "visibility": false + } + ], + "properties": { + "order": 86, + "id": 45, + "prevSize": 32, + "code": 58896, + "name": "system-config" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 45 + }, + { + "icon": { + "paths": [ + "M509.978 54.426l-509.978 509.926 95.949 95.949 414.106-413.978 413.875 413.978 95.949-95.898-509.901-509.978zM146.253 688.563v335.437h259.917v-304.819h207.514v304.819h259.917v-335.488l-363.622-363.597-363.725 363.648z" + ], + "attrs": [ + { + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "home" + ], + "grid": 0 + }, + "attrs": [ + { + "visibility": false + } + ], + "properties": { + "order": 85, + "id": 46, + "prevSize": 32, + "code": 58897, + "name": "home" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 46 + }, + { + "icon": { + "paths": [ + "M0 736.41l498.278 287.59v-421.402l-498.278-287.667v421.478zM894.464 224.486v44.262c0 32.819-62.797 59.418-140.365 59.418-77.466 0-140.262-26.598-140.262-59.418v-73.216h0.435c4.71 30.925 65.408 55.475 139.853 55.475 77.568 0 140.365-26.624 140.365-59.29 0-32.845-62.797-59.366-140.365-59.366-6.195 0-12.262 0.205-18.202 0.563l-90.317-52.147v55.706c0 32.819-62.72 59.392-140.262 59.392-48.691 0-91.597-10.496-116.813-26.47-3.584-3.712-7.987-7.245-13.312-10.598-6.579-6.861-10.24-14.387-10.24-22.323v-53.939l-87.322 50.381c-6.272-0.307-12.646-0.614-19.123-0.614-77.491 0-140.314 26.522-140.314 59.366 0 32.691 62.822 59.29 140.314 59.29 74.445 0 135.219-24.525 139.93-55.475h0.384v73.216c0 32.819-62.746 59.418-140.314 59.418-77.491 0-140.314-26.598-140.314-59.418v-43.622l-108.083 62.31 499.994 288.563 496.691-286.694-112.358-64.768zM646.784 408.013c0 32.794-62.874 59.315-140.365 59.315s-140.339-26.522-140.339-59.315v-73.267h0.41c4.762 30.95 65.459 55.475 139.93 55.475s135.142-24.525 139.904-55.475h0.486v73.267zM525.645 606.234v417.766l498.355-287.718v-417.766l-498.355 287.718zM505.318 118.656c77.542 0 140.262-26.547 140.262-59.315s-62.72-59.315-140.262-59.315c-77.491 0-140.339 26.573-140.339 59.315-0.026 32.768 62.822 59.315 140.339 59.315z" + ], + "attrs": [ + { + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "lego" + ], + "grid": 0 + }, + "attrs": [ + { + "visibility": false + } + ], + "properties": { + "order": 84, + "id": 47, + "prevSize": 32, + "code": 58898, + "name": "lego" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 47 + }, + { + "icon": { + "paths": [ + "M287.002 481.664c0.205 0.23 0.461 0.486 0.691 0.717l103.347 103.373 36.045-36.045-56.55-56.499 90.266-90.189 11.904 1.28c3.046 0.307 6.093 0.538 9.19 0.538 6.246 0 12.314-0.768 18.253-2.125l-66.381-66.381c-1.357-1.382-2.765-2.611-4.173-3.814 20.454-73.6 1.766-155.725-56.038-213.555-57.421-57.421-138.803-76.237-211.968-56.525l123.955 123.981-32.563 121.446-121.395 32.589-124.032-124.006c-19.712 73.19-0.896 154.573 56.525 212.019 60.262 60.288 147.021 77.952 222.925 53.197zM653.235 555.802c-1.997 8.909-2.509 18.202-1.459 27.546l1.306 11.93-90.189 90.189-56.55-56.55-36.070 36.122 327.219 327.194c20.198 20.173 46.618 30.259 73.062 30.259s52.915-10.086 73.037-30.259c40.346-40.32 40.346-105.728 0-146.074l-290.355-290.355zM905.907 958.362l-51.866 13.875-42.112-42.112 13.901-51.891 51.866-13.926 42.112 42.138-13.901 51.917zM506.701 594.099l56.576 56.576 64.128-64.154c-3.482-31.334 6.707-63.821 30.669-87.808 24.013-23.962 56.474-34.176 87.808-30.72l280.397-280.346-157.056-157.056-280.448 280.397c3.482 31.258-6.682 63.821-30.669 87.782-24.013 23.987-56.525 34.176-87.808 30.643l-64.102 64.205 56.499 56.422-277.043 277.12-10.138-10.138-53.248 42.829-89.421 141.312 22.835 22.835 141.312-89.421 42.803-53.222-10.138-10.138 277.043-277.12z" + ], + "attrs": [ + { + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "tool" + ], + "grid": 0 + }, + "attrs": [ + { + "visibility": false + } + ], + "properties": { + "order": 120, + "id": 48, + "prevSize": 32, + "code": 58899, + "name": "tool" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 48 + }, + { + "icon": { + "paths": [ + "M1023.932 505.105c-3.717-282.692-236.1-508.826-518.793-505.003-282.658 3.775-508.826 236.066-505.071 518.827 3.772 282.556 236.1 508.826 518.793 505.003 282.658-3.768 508.826-236.066 505.071-518.827zM623.991 481.304v298.633h-223.983v-298.633h-186.621l298.633-298.633 298.667 298.633h-186.679z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "upgrade" + ], + "grid": 0 + }, + "attrs": [ + {} + ], + "properties": { + "order": 125, + "id": 49, + "prevSize": 32, + "code": 58900, + "name": "upgrade" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 49 + }, + { + "icon": { + "paths": [ + "M870.821 731.837c-64.195-65.89-78.231-188.772-91.738-283.159-20.074-139.937-24.259-297.089-226.008-317.693v-25.318c0-25.424-39.195-46.028-64.937-46.028s-62.024 20.551-62.024 46.028v25.371c-200.054 20.816-206.993 177.914-226.855 317.693-13.453 94.439-27.331 217.268-91.049 283.264-12.818 13.348-16.473 32.998-9.11 49.947 7.362 16.843 24.153 27.913 42.797 27.913h695.343c18.75 0 35.593-11.070 42.903-28.019s3.655-36.653-9.322-50z", + "M489.569 963.883c51.060 0 92.373-40.837 92.373-91.367h-184.694c-0.053 50.53 41.314 91.367 92.32 91.367z" + ], + "width": 989, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "notification-02" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 123, + "id": 50, + "prevSize": 32, + "code": 58887, + "name": "notification-02" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 50 + }, + { + "icon": { + "paths": [ + "M252.137 153.228l-160.070 92.393 378.042 218.205 160.023-92.393-377.996-218.205zM845.638 247.063l-377.996-218.252-145.222 83.828 377.996 218.205 145.222-83.782zM502.784 526.15v433.664l376.832-217.507v-433.711l-376.832 217.553zM55.668 742.26l376.785 217.507v-436.503l-376.785-217.46v436.457z" + ], + "width": 954, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "product" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 7, + "id": 51, + "prevSize": 32, + "code": 58888, + "name": "product", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 51 + }, + { + "icon": { + "paths": [ + "M454.495 48.899l-402.697 240.513v457.026l104.632 60.727v-457.049l298.157-178.728 299.698 179.142-0.138 455.922 103.528-60.013v-457.026l-403.18-240.513zM507.766 330.28v534.344l-53.271 32.124-53.34-32.262v-533.792l-138.090 83.853v456.934l191.453 115.516 193.087-116.322v-456.451l-139.839-83.945z" + ], + "width": 903, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "logo" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 17, + "id": 52, + "prevSize": 32, + "code": 58886, + "name": "logo", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 52 + }, + { + "icon": { + "paths": [ + "M709.921 158.694c8.139 32.295 8.927 34.974 8.192 68.162-0.263 12.813-7.772 71.943-5.724 90.112 1.628 14.966 5.461 16.174 11.448 28.514 10.398 21.425 6.984 51.095 2.941 72.678-2.206 11.868-6.827 28.725-13.916 38.387-7.667 10.66-23.211 10.713-30.142 23.158-9.872 17.854-4.306 43.008-10.503 62.385-7.142 21.898-25.101 23.421-26.466 52.145 8.822 1.155 17.592 2.468 26.466 3.623 8.822 18.59 25.049 55.874 41.59 67.059 13.863 3.728 27.727 7.457 41.59 11.185 48.627 19.64 102.558 43.061 151.237 63.33 44.373 18.432 97.411 24.996 113.48 70.84 0 31.035 2.941 104.501 2.153 145.25h-965.553c-0.893-40.697 2.153-114.215 2.153-145.25 15.964-45.844 69.002-52.408 113.375-70.84 48.679-20.27 102.61-43.691 151.237-63.33 13.811-3.728 27.674-7.457 41.59-11.185 16.489-11.185 32.715-48.522 41.538-67.059l19.692-4.621c-4.464-24.576-19.85-26.466-26.256-43.743-2.521-26.099-5.041-52.145-7.509-78.192 0.053 1.155-18.117-3.361-20.48-4.779-25.731-15.806-26.204-80.24-28.725-107.021-1.103-12.183 16.174-22.265 11.343-44.636-28.094-131.44 12.183-192.88 75.881-213.307 44.216-17.749 126.871-50.465 203.855-3.728l19.167 17.487 30.93 5.251c15.491 8.77 25.416 38.124 25.416 38.124z" + ], + "width": 1090, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "account" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 9, + "id": 53, + "prevSize": 32, + "code": 58880, + "name": "account", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 53 + }, + { + "icon": { + "paths": [ + "M529.203 886.14l-468.465-628.209h936.931l-468.465 628.209z" + ], + "width": 1085, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "arrowdown" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 10, + "id": 54, + "prevSize": 32, + "code": 58881, + "name": "arrowdown", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 54 + }, + { + "icon": { + "paths": [ + "M976.793 982.006h-910.388v-910.388h910.388v910.388zM912.622 135.789h-782.046v782.088h782.046v-782.088z", + "M221.432 822.8h152.876v-372.033h-152.876v372.033z", + "M466.323 820.234h350.932v-366.53h-350.932v366.53z", + "M221.432 360.489h595.865v-147.125h-595.865v147.125z" + ], + "width": 1034, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "cms" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 83, + "id": 55, + "prevSize": 32, + "code": 58882, + "name": "cms", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 55 + }, + { + "icon": { + "paths": [ + "M264.319 308.831c75.685 0 136.98-61.259 136.98-136.944 0-75.649-61.295-136.98-136.98-136.98s-137.017 61.331-137.017 136.98c0 75.649 61.331 136.944 137.017 136.944zM448.929 370.851c-28.962-28.926-63.325-46.252-187.655-46.252s-157.859 18.776-185.335 46.252c-27.44 27.44-18.196 320.43-18.196 320.43l60.824-144.411 38.241 430.334 110.23-220.278 102.907 220.278 36.393-430.334 60.824 144.411c-0.036 0 10.693-291.468-18.233-320.43z" + ], + "width": 489, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "customers" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 82, + "id": 56, + "prevSize": 32, + "code": 58883, + "name": "customers", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 56 + }, + { + "icon": { + "paths": [ + "M680.975 73.728c-337.523 0-610.976 273.515-611.038 610.976 0.122 37.72 1.039 251.812 1.039 251.812h1219.997c0 0 0.978-239.219 1.039-251.812-0.183-337.523-273.637-610.976-611.038-610.976zM737.708 197.831c31.117 3.607 61.379 10.271 90.418 19.624l-19.93 61.685c-25.004-8.070-51.169-13.939-78.191-16.995l7.703-64.313zM270.091 673.15h-64.864c0-31.423 3.118-62.235 8.803-92.007l63.702 12.349c-5.135 25.799-7.642 52.392-7.642 79.658zM305.855 504.419l-59.178-26.288c12.655-28.489 28-55.449 45.79-80.636l52.942 37.475c-15.284 21.825-28.611 45.056-39.554 69.449zM407.46 365.155l-43.405-48.113c22.925-20.541 47.807-39.187 74.462-54.96l33.318 55.571c-22.987 13.755-44.567 29.65-64.374 47.501zM536.943 217.455c29.039-9.292 59.178-16.017 90.418-19.624l7.581 64.313c-26.838 3.057-53.003 8.926-78.13 16.995l-19.869-61.685zM761.673 801.532l-152.897 27.205-38.881-150.452 395.172-404.22-203.394 527.467zM1019.476 434.971l52.942-37.414c17.79 25.187 33.257 52.148 45.851 80.636l-59.178 26.288c-10.943-24.454-24.209-47.685-39.615-69.51zM1094.916 673.15c0-27.266-2.69-53.859-7.703-79.658l63.702-12.349c5.808 29.834 8.803 60.645 8.803 92.007h-64.802zM646.006 770.659c26.777 17.056 62.174 9.415 79.291-17.24 17.118-26.593 9.292-62.051-17.301-79.108-26.655-17.24-62.051-9.354-79.23 17.362-17.118 26.349-9.476 61.99 17.24 78.986z" + ], + "width": 1376, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "dashboard" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 81, + "id": 57, + "prevSize": 32, + "code": 58884, + "name": "dashboard", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 57 + }, + { + "icon": { + "paths": [ + "M24.097 113.465h972.827v111.922l-410.504 412.792v238.366l-171.447 87.505v-325.871l-390.875-415.877v-108.837z" + ], + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "filter" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 80, + "id": 58, + "prevSize": 32, + "code": 58885, + "name": "filter", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 58 + }, + { + "icon": { + "paths": [ + "M59.153 534.182l164.053 38.141v-303.902l-164.053 38.141v227.621zM1122.198 59.153l-837.712 194.959v335.978l140.328 376.832 151.712-57.45-104.049-279.113 649.668 151.18v-722.385z" + ], + "width": 1170, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "promotions" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 79, + "id": 59, + "prevSize": 32, + "code": 58889, + "name": "promotions", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 59 + }, + { + "icon": { + "paths": [ + "M736.707 981.234h207.134v-322.703h-207.134v322.703zM399.646 981.234h207.134v-946.793h-207.134v946.793zM62.673 981.19h207.134v-634.704h-207.134v634.704z" + ], + "width": 991, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "reports" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 78, + "id": 60, + "prevSize": 32, + "code": 58890, + "name": "reports", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 60 + }, + { + "icon": { + "paths": [ + "M426.502 612.517c-15.866-13.512-42.796-25.753-80.79-36.723v198.774c11.535-1.459 23.729-4.331 36.299-8.851 12.618-4.426 23.87-10.829 33.804-19.068 9.981-8.427 18.173-18.55 24.529-30.649 6.638-12.006 9.651-26.365 9.651-42.89 0.047-26.836-7.721-47.222-23.493-60.593zM576.736 736.856c-7.109 23.117-19.774 45.762-38.135 67.749-18.503 22.175-43.079 41.855-74.010 58.992-30.885 17.373-70.432 27.683-118.878 31.12v88.088h-57.014v-88.088c-72.080-5.603-128.483-29.237-169.113-71.374-40.536-42.090-63.935-104.095-70.432-185.544h136.251c-0.753 39.359 8.992 70.479 28.86 93.266 20.15 22.74 44.774 37.335 74.434 43.455v-216.523c-3.060-1.318-7.486-2.919-12.994-4.567-5.508-1.789-11.393-3.343-17.938-4.708-23.776-6.827-47.175-15.019-70.291-24.294-23.493-9.369-44.114-21.704-62.523-37.335-18.456-15.584-33.098-34.84-43.879-57.956-11.111-23.211-16.478-51.977-16.478-86.487 0-35.31 6.168-66.336 18.785-93.313 12.665-26.836 29.143-49.529 49.858-67.702 20.621-18.314 44.303-32.58 71.468-42.419 27.071-10.122 55.037-16.149 83.992-18.314v-79.66h57.014v79.66c29.143 3.531 56.308 10.169 81.638 20.292 25.423 10.028 47.787 23.729 67.137 41.478 19.585 17.514 35.357 39.453 47.457 65.771 12.288 26.13 19.35 57.109 21.28 93.172h-137.287c-0.518-27.636-8.616-51.082-23.917-70.432-15.725-19.303-34.275-29.002-56.308-29.002v183.331c7.862 2.072 15.631 4.143 23.729 6.12 8.098 2.072 16.525 4.567 25.565 7.297 47.645 13.983 84.415 31.12 110.168 51.318 25.8 20.292 44.726 41.666 56.92 63.653 12.335 22.175 19.633 44.256 21.704 66.336 2.448 22.081 3.531 41.713 3.531 59.039 0.047 15.207-3.531 34.416-10.593 57.579zM228.905 263.415c-8.38 7.156-15.113 16.196-19.962 26.883-4.802 10.781-7.062 23.352-7.062 37.759 0 22.834 6.733 40.536 20.103 52.824 13.653 12.618 35.734 22.552 66.713 30.131v-168.831c-10.829 0-21.516 1.695-31.826 5.226-10.216 3.437-19.633 8.851-27.966 16.007z" + ], + "width": 659, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "sales" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 77, + "id": 61, + "prevSize": 32, + "code": 58891, + "name": "sales", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 61 + }, + { + "icon": { + "paths": [ + "M555.139 21.642c-218.775-71.601-457.062 40.29-532.231 250.028-75.227 209.681 41.211 437.665 259.928 509.208 218.717 71.601 457.004-40.348 532.231-250.028s-41.211-437.665-259.928-509.208zM320.076 677.045c-158.915-52.089-243.467-217.681-188.903-369.978 54.679-152.296 227.754-233.625 386.669-181.593s243.409 217.624 188.788 369.92c-54.622 152.296-227.696 233.567-386.554 181.65z", + "M638.482 685.794l358.927 349.602 24.807-69.241 24.865-69.241-310.348-302.29z" + ], + "width": 1109, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "search" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + }, + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 76, + "id": 62, + "prevSize": 32, + "code": 58892, + "name": "search", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 62 + }, + { + "icon": { + "paths": [ + "M1098.281 85.45c19.777-3.723 34.901-21.232 34.901-42.347-0.058-23.791-19.196-43.103-42.812-43.103h-900.508c-23.675 0-42.754 19.312-42.754 43.103 0 21.057 15.007 38.566 34.843 42.347l-181.951 354.421v68.988c0 30.946 32.516 56.016 72.594 56.016 13.437 0 26.001-2.908 36.821-7.795v466.919h1061.286v-466.919c10.878 4.944 23.326 7.795 36.879 7.795 40.078 0 72.594-25.071 72.594-56.016v-68.988l-181.893-354.421zM214.758 564.875c-38.217 0-69.221-25.071-69.221-56.016v-6.457h-0.349v-62.531l137.162-353.665h109.648l-107.961 353.665v68.988c0 0 0 0 0 0 0 30.946-31.004 56.016-69.279 56.016zM498.447 564.875c-38.217 0-69.221-25.071-69.221-56.016v-68.988l57.354-353.665h109.241l-28.095 353.665v68.93c-0.058 31.004-31.004 56.075-69.279 56.075zM782.077 564.875c-38.217 0-69.162-25.071-69.162-56.016v-68.988l-28.154-353.665h108.892l57.296 353.665v68.988c0 0.931 0.175 1.92 0.233 2.792-1.803 29.666-32.051 53.224-69.104 53.224zM1134.637 508.859c0 30.946-31.004 56.016-69.221 56.016s-69.162-25.071-69.162-56.016v-68.988l-108.019-353.665h109.59l137.22 353.665v62.473h-0.349v6.515h-0.058z" + ], + "width": 1280, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "stores" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 75, + "id": 63, + "prevSize": 32, + "code": 58893, + "name": "stores", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 63 + }, + { + "icon": { + "paths": [ + "M944.97 329.042c-97.861 0-177.522 79.581-177.522 177.443 0 97.94 79.66 177.679 177.522 177.679 98.019 0 177.679-79.739 177.679-177.679 0-97.861-79.66-177.443-177.679-177.443zM944.97-0c-470.712 0-944.97 512-944.97 512s474.258 512 944.97 512c470.949 0 945.128-512 945.128-512s-474.179-512-945.128-512zM944.97 868.856c-200.057 0-362.292-162.078-362.292-362.45 0-200.057 162.236-362.292 362.292-362.292 200.214 0 362.45 162.236 362.45 362.292 0 200.451-162.236 362.45-362.45 362.45z" + ], + "width": 1890, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "views" + ], + "grid": 0 + }, + "attrs": [ + { + "opacity": 1, + "visibility": false + } + ], + "properties": { + "order": 73, + "id": 64, + "prevSize": 32, + "code": 58895, + "name": "views", + "ligatures": "" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 64 + }, + { + "icon": { + "paths": [ + "M1042.226 299.849h-598.393v-299.849l-443.833 384.316 443.833 384.403v-299.859h598.393c106.478 0 192.801 86.318 192.801 192.801s-86.318 192.796-192.801 192.796v0.483l-452.707 0.005c-46.695 0.005-84.53 37.845-84.53 84.535 0 46.68 37.84 84.525 84.535 84.525 0.377 0 0.744-0.053 1.121-0.058h451.581c199.964 0 362.044-162.085 362.044-362.039 0-199.964-162.080-362.059-362.044-362.059z" + ], + "width": 1404, + "attrs": [], + "isMulticolor": false, + "isMulticolor2": false, + "tags": [ + "revert" + ], + "grid": 0 + }, + "attrs": [], + "properties": { + "order": 129, + "id": 65, + "prevSize": 32, + "code": 58946, + "name": "revert" + }, + "setIdx": 1, + "setId": 1, + "iconIdx": 65 } + ], + "height": 1024, + "metadata": { + "name": "icomoon" + }, + "preferences": { + "showGlyphs": true, + "showQuickUse": true, + "showQuickUse2": true, + "showSVGs": true, + "fontPref": { + "prefix": "icon-", + "metadata": { + "fontFamily": "icomoon", + "majorVersion": 1, + "minorVersion": 0 + }, + "metrics": { + "emSize": 1024, + "baseline": 6.25, + "whitespace": 50 + }, + "resetPoint": 58880, + "showVersion": true, + "showSelector": false, + "showMetrics": false, + "showMetadata": false, + "embed": false + }, + "imagePref": { + "prefix": "icon-", + "png": true, + "useClassSelector": true, + "classSelector": ".icon" + }, + "historySize": 100, + "showCodes": true, + "search": "", + "gridSize": 16, + "showLiga": false + } } \ No newline at end of file diff --git a/app/design/adminhtml/Magento/backend/web/js/theme.js b/app/design/adminhtml/Magento/backend/web/js/theme.js index 28c69d5835908..0be4fbbe07c54 100644 --- a/app/design/adminhtml/Magento/backend/web/js/theme.js +++ b/app/design/adminhtml/Magento/backend/web/js/theme.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/clearless/_all.less b/app/design/adminhtml/Magento/backend/web/mui/clearless/_all.less index 9e9946de1850b..109efa2b4e24f 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/clearless/_all.less +++ b/app/design/adminhtml/Magento/backend/web/mui/clearless/_all.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/clearless/_arrows.less b/app/design/adminhtml/Magento/backend/web/mui/clearless/_arrows.less index f34a52c265073..e0128b55b9bdd 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/clearless/_arrows.less +++ b/app/design/adminhtml/Magento/backend/web/mui/clearless/_arrows.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/clearless/_helpers.less b/app/design/adminhtml/Magento/backend/web/mui/clearless/_helpers.less index 923f371e91b9c..332f8500789a2 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/clearless/_helpers.less +++ b/app/design/adminhtml/Magento/backend/web/mui/clearless/_helpers.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/clearless/_icons.less b/app/design/adminhtml/Magento/backend/web/mui/clearless/_icons.less index 12a17f1e63eb2..62ff49de8719d 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/clearless/_icons.less +++ b/app/design/adminhtml/Magento/backend/web/mui/clearless/_icons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/clearless/_settings.less b/app/design/adminhtml/Magento/backend/web/mui/clearless/_settings.less index 176a4feacd1ce..df46f4e8ae1dd 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/clearless/_settings.less +++ b/app/design/adminhtml/Magento/backend/web/mui/clearless/_settings.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/clearless/_sprites.less b/app/design/adminhtml/Magento/backend/web/mui/clearless/_sprites.less index 56fcc6f5233eb..97c59a9ff0617 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/clearless/_sprites.less +++ b/app/design/adminhtml/Magento/backend/web/mui/clearless/_sprites.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/styles/_abstract.less b/app/design/adminhtml/Magento/backend/web/mui/styles/_abstract.less index 3f76ac127ea33..a615eb010f7e9 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/styles/_abstract.less +++ b/app/design/adminhtml/Magento/backend/web/mui/styles/_abstract.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/styles/_base.less b/app/design/adminhtml/Magento/backend/web/mui/styles/_base.less index d33622889518b..9680e5ddba31d 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/styles/_base.less +++ b/app/design/adminhtml/Magento/backend/web/mui/styles/_base.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less b/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less index 03856d833c889..91f509d24a2f0 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less +++ b/app/design/adminhtml/Magento/backend/web/mui/styles/_table.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/adminhtml/Magento/backend/web/mui/styles/_vars.less b/app/design/adminhtml/Magento/backend/web/mui/styles/_vars.less index 24f9fa1fd8362..2839b4280b203 100644 --- a/app/design/adminhtml/Magento/backend/web/mui/styles/_vars.less +++ b/app/design/adminhtml/Magento/backend/web/mui/styles/_vars.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_module.less index 5d90d961d3e15..4678f33773f55 100644 --- a/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_widgets.less index 201358436e3d3..bb7f91210911e 100644 --- a/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_AdvancedCheckout/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less index ac6344403f30f..910fac15f50e8 100644 --- a/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_Banner/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Braintree/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Braintree/web/css/source/_module.less index 00716c776990d..566f6ab001aa9 100644 --- a/app/design/frontend/Magento/blank/Magento_Braintree/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Braintree/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_email.less b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_email.less index 3dbdb6373da90..4ac5db27a01c6 100644 --- a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_email.less +++ b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_email.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less index 7ecfe2ff3ceb1..a1845fca96ce8 100644 --- a/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Bundle/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less index 95de500a8c3d3..807effcd1c3b7 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_widgets.less index 5347bc3c59e9e..eca3e5f0d7837 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less index d3dc6882899c4..ebfddbec73f4d 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less index 7e6c9797e43a6..c552295ceb006 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -50,8 +50,6 @@ } .limiter { - display: none; - .control { display: inline-block; } @@ -83,9 +81,11 @@ ); } - .sorter.sort-desc { - &:before { - content: @icon-arrow-down; + .sorter { + .sort-desc { + &:before { + content: @icon-arrow-down; + } } } diff --git a/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_module.less index 60dcd6b8be8a8..989f7fbd093b9 100644 --- a/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_widgets.less index 020578d559208..11133accae608 100644 --- a/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_CatalogEvent/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less index 18620f2ee863e..5cc37fbaf640c 100644 --- a/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_CatalogSearch/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less index da9d5a8018944..afaa3a485cefe 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less index 0190db584745e..b23a949ec7232 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_cart.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_checkout.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_checkout.less index 235bec40009eb..471b177201300 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_checkout.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_checkout.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less index 4f5bd4da26a34..cbaa177cfb914 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less index f7350cd7285a4..57a64fe013f3b 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_authentication.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout-agreements.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout-agreements.less index a4a5ebc72f078..b1f5c31fac08c 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout-agreements.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout-agreements.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less index 3804721026db5..3ee6c7bbdbd8d 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_checkout.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -23,8 +23,7 @@ & when (@media-common = true) { - .checkout-index-index, - .checkout-onepage-success { + .checkout-index-index { .page-title-wrapper { &:extend(.abs-visually-hidden all); } @@ -61,6 +60,14 @@ margin-left: 0; } } + + .checkout-onepage-success { + &:extend(.abs-add-clearfix all); + + .print { + display: none; + } + } } // @@ -87,4 +94,12 @@ .lib-layout-column(2, 1, @checkout-wrapper__columns); padding-right: @indent__l; } + + .checkout-onepage-success { + .print { + display: block; + float: right; + margin: 22px 0 0; + } + } } diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less index f3ff064db55e6..0dce95d4755fa 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_fields.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_fields.less index d43b8b1a09de1..b6a2b9a0471d4 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_fields.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_fields.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_modals.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_modals.less index ce3a3ac9314a4..f88237ce924fc 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_modals.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_modals.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_order-summary.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_order-summary.less index a1ec6480827fd..d3bae983a2ece 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_order-summary.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_order-summary.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less index a509970552d74..1941d1de742c2 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payment-options.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less index ca69275441643..89a5492a6df4c 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -24,6 +24,7 @@ & when (@media-common = true) { .checkout-payment-method { .step-title { + border-bottom: 0; margin-bottom: 0; } @@ -39,6 +40,12 @@ display: block; } } + + & + .payment-method { + .payment-method-title { + .lib-css(border-top, @checkout-payment-method-title__border); + } + } } .payment-method-content { @@ -54,7 +61,6 @@ } .payment-method-title { - .lib-css(border-top, @checkout-payment-method-title__border); .lib-css(padding, @checkout-payment-method-title__padding 0); margin: 0; @@ -72,7 +78,6 @@ .payment-method-content { display: none; - .lib-css(padding, 0 0 @indent__base @checkout-payment-method-content__padding__xl); .fieldset { &:not(:last-child) { @@ -81,6 +86,14 @@ } } + .payment-group { + & + .payment-group { + .step-title { + margin: @indent__base 0 0; + } + } + } + .field-select-billing, .billing-address-form { .lib-css(max-width, @checkout-billing-address-form__max-width); @@ -90,7 +103,7 @@ margin: 0 0 @indent__s; } - .payment-method-billing-address { + .checkout-billing-address { margin: 0 0 @indent__base; .primary { @@ -106,15 +119,11 @@ .billing-address-details { .lib-css(line-height, @checkout-billing-address-details__line-height); .lib-css(padding, @checkout-billing-address-details__padding); - - .action-edit-address { - &:extend(.abs-action-button-as-link all); - } } } .payment-method-note { - & + .payment-method-billing-address { + & + .checkout-billing-address { margin-top: @indent__base; } } @@ -161,7 +170,7 @@ .lib-css(padding, 0 @checkout-payment-method-title-mobile__padding @indent__base); } - .payment-method-billing-address { + .checkout-billing-address { .action-cancel { margin-top: @indent__s; } @@ -175,12 +184,10 @@ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .checkout-payment-method { - .payment-methods { - .actions-toolbar { - .primary { - float: right; - margin: 0; - } + .actions-toolbar { + .primary { + float: right; + margin: 0; } } @@ -214,7 +221,7 @@ } } - .payment-method-billing-address { + .checkout-billing-address { .action-update { float: right; } diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less index b5e05d44ccc60..dd36296001be8 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping-policy.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping-policy.less index 980e548f49467..af58b22767c5a 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping-policy.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping-policy.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less index 2379bfc9fa66f..bb43343cdbc6b 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_shipping.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar-shipping-information.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar-shipping-information.less index 9cd27e48e3b55..6f9945c694e93 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar-shipping-information.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar-shipping-information.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar.less index f78982054f505..f623dca9cc386 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_sidebar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less index 114e6e5c1fe31..3f97dc6fa2328 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Cms/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_Cms/web/css/source/_widgets.less index 944f593cae736..ca1146c45d6b1 100644 --- a/app/design/frontend/Magento/blank/Magento_Cms/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_Cms/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less index 369e100506c4d..a9028fa65cebf 100644 --- a/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Customer/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -15,6 +15,8 @@ @account-nav-current-color: false; @account-nav-current-font-weight: @font-weight__semibold; +@account-nav-delimiter__border-color: @color-gray82; + @account-nav-item-hover: @color-gray91; @_password-default: @color-gray-light01; @@ -219,6 +221,12 @@ .lib-css(border-color, @account-nav-current-border-color); } } + + .delimiter { + border-top: 1px solid @account-nav-delimiter__border-color; + display: block; + margin: @indent__s 1.8rem; + } } } @@ -484,15 +492,23 @@ .block-addresses-list { .items.addresses { &:extend(.abs-add-clearfix-desktop all); + font-size: 0; > .item { - &:extend(.abs-blocks-2columns all); + display: inline-block; + font-size: @font-size__base; margin-bottom: @indent__base; + vertical-align: top; + width: 48.8%; &:nth-last-child(1), &:nth-last-child(2) { margin-bottom: 0; } + + &:nth-child(even) { + margin-left: 2.4%; + } } } } diff --git a/app/design/frontend/Magento/blank/Magento_Downloadable/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Downloadable/web/css/source/_module.less index a7fccdac8b10c..102ae8558527a 100644 --- a/app/design/frontend/Magento/blank/Magento_Downloadable/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Downloadable/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_GiftCard/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftCard/web/css/source/_module.less index 32edcb1872353..6a452c44b5e96 100644 --- a/app/design/frontend/Magento/blank/Magento_GiftCard/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_GiftCard/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_GiftCardAccount/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftCardAccount/web/css/source/_module.less index 73e209cf83262..c4494ceb81baa 100644 --- a/app/design/frontend/Magento/blank/Magento_GiftCardAccount/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_GiftCardAccount/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less index 59ee7d7dcc472..914532dfd1542 100644 --- a/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_GiftMessage/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less index ae8c39721c30d..e465c16d143ca 100644 --- a/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_widgets.less index fad3bc44455a2..8fc75aea3996e 100644 --- a/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_GiftRegistry/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less index b4665dbd62e96..e5616a422f897 100644 --- a/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_GiftWrapping/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_GroupedProduct/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_GroupedProduct/web/css/source/_module.less index cfe025532a80c..bd2ec7a53cb37 100644 --- a/app/design/frontend/Magento/blank/Magento_GroupedProduct/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_GroupedProduct/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Invitation/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Invitation/web/css/source/_module.less index 49dbd94365fb7..e120ae3f2e406 100644 --- a/app/design/frontend/Magento/blank/Magento_Invitation/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Invitation/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less index 998f31ece65be..88a8aca616a24 100644 --- a/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_LayeredNavigation/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Msrp/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Msrp/web/css/source/_module.less index 198e9e37feccd..3ec5d7b7f4284 100644 --- a/app/design/frontend/Magento/blank/Magento_Msrp/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Msrp/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less index 9d69489050691..1ae47c6768718 100644 --- a/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_widgets.less index 5c607eff1ad9b..9fd5088b76c8e 100644 --- a/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_MultipleWishlist/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less index 9db60b10f0efb..07e0bb898eec3 100644 --- a/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Multishipping/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less index e1513253ce0e2..c3457924653d3 100644 --- a/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Newsletter/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/_module.less index c35ab69646b13..d31fdc09c8353 100644 --- a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_billing.less b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_billing.less index 256bba42c8826..51742671f4d22 100644 --- a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_billing.less +++ b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_billing.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_paypal-button.less b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_paypal-button.less index f50bf8f2b8af5..1766c5e093df4 100644 --- a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_paypal-button.less +++ b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_paypal-button.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_review.less b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_review.less index 99101675ea3cd..4f76a3858f108 100644 --- a/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_review.less +++ b/app/design/frontend/Magento/blank/Magento_Paypal/web/css/source/module/_review.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less index 945065315baab..b35921e89b435 100644 --- a/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_ProductVideo/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Reports/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_Reports/web/css/source/_widgets.less index 67ab473589a09..c16c6c5204769 100644 --- a/app/design/frontend/Magento/blank/Magento_Reports/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_Reports/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less index 20b3af56588b8..5d7777c8d0a32 100644 --- a/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Review/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Reward/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Reward/web/css/source/_module.less index 627b319422d5c..132ba29ab8a71 100644 --- a/app/design/frontend/Magento/blank/Magento_Reward/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Reward/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_email.less b/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_email.less index 473b165a9f0bd..65ca8363f417b 100644 --- a/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_email.less +++ b/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_email.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less index a8d0bf8b58482..7f6255ee870d1 100644 --- a/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Rma/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -158,11 +158,12 @@ .block-returns-tracking { .block-title { .action { - margin: 12px 0 0 30px; + margin: 0 0 0 30px; + } - &.track { - float: right; - } + .actions-track { + float: right; + margin-top: 12px; } } } diff --git a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less index aab53314a25d1..45f880bc4779c 100644 --- a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less +++ b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_module.less index 905de8ea20681..dd06e293bdde3 100644 --- a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_widgets.less index a989b406e3cca..a14ebbb81acd8 100644 --- a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_SalesRule/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_SalesRule/web/css/source/_module.less index a7f075f553dc3..25d3dd37763be 100644 --- a/app/design/frontend/Magento/blank/Magento_SalesRule/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_SalesRule/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_SendFriend/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_SendFriend/web/css/source/_module.less index e15ff2f66c566..c7aeac2184a6b 100644 --- a/app/design/frontend/Magento/blank/Magento_SendFriend/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_SendFriend/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Theme/layout/default_head_blocks.xml b/app/design/frontend/Magento/blank/Magento_Theme/layout/default_head_blocks.xml index 4e911e4b38e24..c4681a4c21579 100644 --- a/app/design/frontend/Magento/blank/Magento_Theme/layout/default_head_blocks.xml +++ b/app/design/frontend/Magento/blank/Magento_Theme/layout/default_head_blocks.xml @@ -1,7 +1,7 @@ diff --git a/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less index 3b8e84da84106..9b2634cfa7e37 100644 --- a/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -112,6 +112,11 @@ } } + .action-skip-wrapper { + height: 0; + position: relative; + } + // // Global notice // --------------------------------------------- diff --git a/app/design/frontend/Magento/blank/Magento_Vault/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Vault/web/css/source/_module.less index b6f60c6e80074..6d8680f434af1 100644 --- a/app/design/frontend/Magento/blank/Magento_Vault/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Vault/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_VersionsCms/web/css/source/_widgets.less b/app/design/frontend/Magento/blank/Magento_VersionsCms/web/css/source/_widgets.less index e9774357cfe5d..589489b068eec 100644 --- a/app/design/frontend/Magento/blank/Magento_VersionsCms/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/blank/Magento_VersionsCms/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Weee/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Weee/web/css/source/_module.less index 13b2f15750fca..be363e146e5b1 100644 --- a/app/design/frontend/Magento/blank/Magento_Weee/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Weee/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less index 2a57f6d011285..d741c28f685e7 100644 --- a/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Wishlist/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/composer.json b/app/design/frontend/Magento/blank/composer.json index 27ed40860dd5b..7c03167ebc232 100644 --- a/app/design/frontend/Magento/blank/composer.json +++ b/app/design/frontend/Magento/blank/composer.json @@ -2,7 +2,7 @@ "name": "magento/theme-frontend-blank", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/framework": "100.2.*" }, "type": "magento2-theme", diff --git a/app/design/frontend/Magento/blank/etc/view.xml b/app/design/frontend/Magento/blank/etc/view.xml index 3a92ad0a67410..13b6586781d54 100644 --- a/app/design/frontend/Magento/blank/etc/view.xml +++ b/app/design/frontend/Magento/blank/etc/view.xml @@ -1,7 +1,7 @@ @@ -73,10 +73,18 @@ 140 + + false + 700700 + + 700 + 700 + false + 9090 @@ -227,7 +235,7 @@ - dots + dots diff --git a/app/design/frontend/Magento/blank/registration.php b/app/design/frontend/Magento/blank/registration.php index 7c2305ef759b7..e3aef3dec6491 100644 --- a/app/design/frontend/Magento/blank/registration.php +++ b/app/design/frontend/Magento/blank/registration.php @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/blank/web/css/_styles.less b/app/design/frontend/Magento/blank/web/css/_styles.less index 75bb1eb1ce17d..e8606965fc6ea 100644 --- a/app/design/frontend/Magento/blank/web/css/_styles.less +++ b/app/design/frontend/Magento/blank/web/css/_styles.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/css/email-fonts.less b/app/design/frontend/Magento/blank/web/css/email-fonts.less index cb4cb3e0d2fee..bff71061e409e 100644 --- a/app/design/frontend/Magento/blank/web/css/email-fonts.less +++ b/app/design/frontend/Magento/blank/web/css/email-fonts.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/css/email-inline.less b/app/design/frontend/Magento/blank/web/css/email-inline.less index 88fef1b1f9f35..861249177641b 100644 --- a/app/design/frontend/Magento/blank/web/css/email-inline.less +++ b/app/design/frontend/Magento/blank/web/css/email-inline.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/css/email.less b/app/design/frontend/Magento/blank/web/css/email.less index 1cff19d649908..496a7664f0cd8 100644 --- a/app/design/frontend/Magento/blank/web/css/email.less +++ b/app/design/frontend/Magento/blank/web/css/email.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/css/print.less b/app/design/frontend/Magento/blank/web/css/print.less index 8f989bf7f78af..1d8ea3b911467 100644 --- a/app/design/frontend/Magento/blank/web/css/print.less +++ b/app/design/frontend/Magento/blank/web/css/print.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less b/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less index cc29dc96a6268..712b34337ef8e 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less +++ b/app/design/frontend/Magento/blank/web/css/source/_actions-toolbar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_breadcrumbs.less b/app/design/frontend/Magento/blank/web/css/source/_breadcrumbs.less index 47ae69fcf6f1b..979bf4b4845f9 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_breadcrumbs.less +++ b/app/design/frontend/Magento/blank/web/css/source/_breadcrumbs.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_buttons.less b/app/design/frontend/Magento/blank/web/css/source/_buttons.less index a1fde5332ec6a..fd4f59daa0cd9 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_buttons.less +++ b/app/design/frontend/Magento/blank/web/css/source/_buttons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_components.less b/app/design/frontend/Magento/blank/web/css/source/_components.less index 5156b710c6100..884339cbd735e 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_components.less +++ b/app/design/frontend/Magento/blank/web/css/source/_components.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_email-base.less b/app/design/frontend/Magento/blank/web/css/source/_email-base.less index 19b432a79481f..1edce5c72c4b9 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_email-base.less +++ b/app/design/frontend/Magento/blank/web/css/source/_email-base.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_email-extend.less b/app/design/frontend/Magento/blank/web/css/source/_email-extend.less index c4f138ead68ad..054bf0361c3b8 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_email-extend.less +++ b/app/design/frontend/Magento/blank/web/css/source/_email-extend.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_email-variables.less b/app/design/frontend/Magento/blank/web/css/source/_email-variables.less index 9ce834ec393b8..78f4ca18c0638 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_email-variables.less +++ b/app/design/frontend/Magento/blank/web/css/source/_email-variables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_extends.less b/app/design/frontend/Magento/blank/web/css/source/_extends.less index 61a4b2675ca65..a174db1f01f9b 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_extends.less +++ b/app/design/frontend/Magento/blank/web/css/source/_extends.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_forms.less b/app/design/frontend/Magento/blank/web/css/source/_forms.less index 72e014b8305aa..8f8f487904397 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_forms.less +++ b/app/design/frontend/Magento/blank/web/css/source/_forms.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -92,10 +92,15 @@ } } + .field-error, div.mage-error[generated] { margin-top: 7px; } + .field-error { + .lib-form-validation-note(); + } + .field .tooltip { .lib-tooltip(right); .tooltip-content { diff --git a/app/design/frontend/Magento/blank/web/css/source/_icons.less b/app/design/frontend/Magento/blank/web/css/source/_icons.less index 9b8d40c532f7c..f35eade77d7ff 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_icons.less +++ b/app/design/frontend/Magento/blank/web/css/source/_icons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_layout.less b/app/design/frontend/Magento/blank/web/css/source/_layout.less index 097fb39798b1b..66195d80a53ad 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_layout.less +++ b/app/design/frontend/Magento/blank/web/css/source/_layout.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_loaders.less b/app/design/frontend/Magento/blank/web/css/source/_loaders.less index 7cc1bc8cdede0..7cfc10c7d2fd3 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_loaders.less +++ b/app/design/frontend/Magento/blank/web/css/source/_loaders.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_messages.less b/app/design/frontend/Magento/blank/web/css/source/_messages.less index 872c216d50b01..e64dbc9af4f11 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_messages.less +++ b/app/design/frontend/Magento/blank/web/css/source/_messages.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_navigation.less b/app/design/frontend/Magento/blank/web/css/source/_navigation.less index fc29da74ba74f..fd5ed9db8811a 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_navigation.less +++ b/app/design/frontend/Magento/blank/web/css/source/_navigation.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_pages.less b/app/design/frontend/Magento/blank/web/css/source/_pages.less index 878e11beb271a..e0b5f435cae61 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_pages.less +++ b/app/design/frontend/Magento/blank/web/css/source/_pages.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_popups.less b/app/design/frontend/Magento/blank/web/css/source/_popups.less index 79d26049e800a..54b55949e197c 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_popups.less +++ b/app/design/frontend/Magento/blank/web/css/source/_popups.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_price.less b/app/design/frontend/Magento/blank/web/css/source/_price.less index 463061c8a0688..a7fbc18c11be3 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_price.less +++ b/app/design/frontend/Magento/blank/web/css/source/_price.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_reset.less b/app/design/frontend/Magento/blank/web/css/source/_reset.less index 092db0dab4f8b..7b21ea075f6e3 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_reset.less +++ b/app/design/frontend/Magento/blank/web/css/source/_reset.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_sections.less b/app/design/frontend/Magento/blank/web/css/source/_sections.less index 33aede5bbcec5..d5f67897abf13 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_sections.less +++ b/app/design/frontend/Magento/blank/web/css/source/_sections.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_sources.less b/app/design/frontend/Magento/blank/web/css/source/_sources.less index 7c7681e2aa2cb..4159c74be5b2e 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_sources.less +++ b/app/design/frontend/Magento/blank/web/css/source/_sources.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_tables.less b/app/design/frontend/Magento/blank/web/css/source/_tables.less index 18cda2ce4a024..ce2c54e13c60d 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_tables.less +++ b/app/design/frontend/Magento/blank/web/css/source/_tables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_theme.less b/app/design/frontend/Magento/blank/web/css/source/_theme.less index c0f6a214ae124..c32bb3a2d071f 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_theme.less +++ b/app/design/frontend/Magento/blank/web/css/source/_theme.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_tooltips.less b/app/design/frontend/Magento/blank/web/css/source/_tooltips.less index 4b6f7d2b4d329..191f4dd6a9e13 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_tooltips.less +++ b/app/design/frontend/Magento/blank/web/css/source/_tooltips.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_typography.less b/app/design/frontend/Magento/blank/web/css/source/_typography.less index acf8d2b14251c..423f03fa789a1 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_typography.less +++ b/app/design/frontend/Magento/blank/web/css/source/_typography.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/_variables.less b/app/design/frontend/Magento/blank/web/css/source/_variables.less index dd855399a5503..fd5c3ffcb06e9 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_variables.less +++ b/app/design/frontend/Magento/blank/web/css/source/_variables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less index 190fd9a8137da..74b5d0ebb7500 100644 --- a/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less +++ b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/blank/web/css/styles-l.less b/app/design/frontend/Magento/blank/web/css/styles-l.less index 30ffcf1d7bde0..639f65db6d197 100644 --- a/app/design/frontend/Magento/blank/web/css/styles-l.less +++ b/app/design/frontend/Magento/blank/web/css/styles-l.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/css/styles-m.less b/app/design/frontend/Magento/blank/web/css/styles-m.less index a8d90150acb47..a1fb0f1d2aefb 100644 --- a/app/design/frontend/Magento/blank/web/css/styles-m.less +++ b/app/design/frontend/Magento/blank/web/css/styles-m.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/js/navigation-menu.js b/app/design/frontend/Magento/blank/web/js/navigation-menu.js index 33ca217565f10..93c2b209c9755 100644 --- a/app/design/frontend/Magento/blank/web/js/navigation-menu.js +++ b/app/design/frontend/Magento/blank/web/js/navigation-menu.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*jshint jquery:true*/ diff --git a/app/design/frontend/Magento/blank/web/js/responsive.js b/app/design/frontend/Magento/blank/web/js/responsive.js index 0174007f428aa..0a539ee635299 100644 --- a/app/design/frontend/Magento/blank/web/js/responsive.js +++ b/app/design/frontend/Magento/blank/web/js/responsive.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/app/design/frontend/Magento/blank/web/js/theme.js b/app/design/frontend/Magento/blank/web/js/theme.js index 2b7c80acd89f6..5f7e20c669bfa 100644 --- a/app/design/frontend/Magento/blank/web/js/theme.js +++ b/app/design/frontend/Magento/blank/web/js/theme.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_module.less index dc2bfce39e9a7..4c66e3995992c 100644 --- a/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_widgets.less b/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_widgets.less index 1cbec5a661745..3a7b4c2a5b8d8 100644 --- a/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_widgets.less +++ b/app/design/frontend/Magento/luma/Magento_AdvancedCheckout/web/css/source/_widgets.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_AdvancedSearch/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_AdvancedSearch/web/css/source/_module.less index a6b33025ca5c7..5438608a3032d 100644 --- a/app/design/frontend/Magento/luma/Magento_AdvancedSearch/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_AdvancedSearch/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less index 7a3931e4484aa..8283bf0519333 100644 --- a/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Bundle/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/layout/catalog_product_view.xml b/app/design/frontend/Magento/luma/Magento_Catalog/layout/catalog_product_view.xml index 251db00247e0a..f3be9746079e8 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/layout/catalog_product_view.xml +++ b/app/design/frontend/Magento/luma/Magento_Catalog/layout/catalog_product_view.xml @@ -1,7 +1,7 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/layout/default.xml b/app/design/frontend/Magento/luma/Magento_Catalog/layout/default.xml index bbc1bdbd60d48..e2ca86189e39a 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/layout/default.xml +++ b/app/design/frontend/Magento/luma/Magento_Catalog/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less index 82d427cdbea96..d32f78a67cb52 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less index 37f73dd37763a..8beec40df9044 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less index 44a400370299f..4b30cc98d58d1 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -115,8 +115,6 @@ } .limiter { - display: none; - &-options { margin: 0 5px 0 7px; width: auto; diff --git a/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less index 2864848720728..009188f578cc7 100644 --- a/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_CatalogSearch/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/layout/checkout_cart_index.xml b/app/design/frontend/Magento/luma/Magento_Checkout/layout/checkout_cart_index.xml index 4a03fab82f0cf..02f68f776f98b 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/layout/checkout_cart_index.xml +++ b/app/design/frontend/Magento/luma/Magento_Checkout/layout/checkout_cart_index.xml @@ -1,7 +1,7 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less index da9d5a8018944..afaa3a485cefe 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less index 5473186d3cb0e..d0640f8f8445f 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_cart.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less index 0db3794e75a8b..f8f12a9c19e99 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less index f037c1c5777cb..d6a1a964286c8 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -27,8 +27,7 @@ & when (@media-common = true) { - .checkout-index-index, - .checkout-onepage-success { + .checkout-index-index { .page-title-wrapper { &:extend(.abs-visually-hidden all); } @@ -66,6 +65,14 @@ margin-left: 0; } } + + .checkout-onepage-success { + &:extend(.abs-add-clearfix all); + + .print { + display: none; + } + } } // @@ -96,4 +103,12 @@ .lib-layout-column(2, 1, @checkout-wrapper__columns); padding-right: @indent__l; } + + .checkout-onepage-success { + .print { + display: block; + float: right; + margin: 23px 0 0; + } + } } diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less index 77e47125bd7c9..584b0b51afabc 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_estimated-total.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_fields.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_fields.less index 3fe6f21f45ceb..894c99b608ea7 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_fields.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_fields.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_modals.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_modals.less index a82d3be735a03..43b9e0605f229 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_modals.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_modals.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_order-summary.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_order-summary.less index beee551041740..6e5ad12d9a74e 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_order-summary.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_order-summary.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payment-options.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payment-options.less index 8b76bc544d58c..4b6be1b7fbac3 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payment-options.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payment-options.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less index 3c3ee77ed00e0..b4d998534445b 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -24,6 +24,7 @@ & when (@media-common = true) { .checkout-payment-method { .step-title { + border-bottom: 0; margin-bottom: 0; } @@ -39,6 +40,12 @@ display: block; } } + + & + .payment-method { + .payment-method-title { + .lib-css(border-top, @checkout-payment-method-title__border); + } + } } .payment-method-content { @@ -54,7 +61,6 @@ } .payment-method-title { - .lib-css(border-top, @checkout-payment-method-title__border); .lib-css(padding, @checkout-payment-method-title__padding 0); margin: 0; @@ -80,6 +86,14 @@ } } + .payment-group { + & + .payment-group { + .step-title { + margin: @indent__base 0 0; + } + } + } + .field-select-billing, .billing-address-form { .lib-css(max-width, @checkout-billing-address-form__max-width); @@ -89,7 +103,7 @@ margin: 0 0 @indent__s; } - .payment-method-billing-address { + .checkout-billing-address { margin: 0 0 @indent__base; .primary { @@ -105,15 +119,11 @@ .billing-address-details { .lib-css(line-height, @checkout-billing-address-details__line-height); .lib-css(padding, @checkout-billing-address-details__padding); - - .action-edit-address { - &:extend(.abs-action-button-as-link all); - } } } .payment-method-note { - & + .payment-method-billing-address { + & + .checkout-billing-address { margin-top: @indent__base; } } @@ -160,7 +170,7 @@ .lib-css(padding, 0 @checkout-payment-method-title-mobile__padding @indent__base); } - .payment-method-billing-address { + .checkout-billing-address { .action-cancel { margin-top: @indent__s; } @@ -174,12 +184,10 @@ .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { .checkout-payment-method { - .payment-methods { - .actions-toolbar { - .primary { - float: right; - margin: 0; - } + .actions-toolbar { + .primary { + float: right; + margin: 0; } } @@ -193,7 +201,7 @@ } } - .payment-method-billing-address { + .checkout-billing-address { .action-update { float: right; } diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less index 298ceb04d2125..f8f557960971e 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_progress-bar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less index a82c4d32e61bf..702ae31478a1d 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_shipping.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Customer/email/account_new.html b/app/design/frontend/Magento/luma/Magento_Customer/email/account_new.html index 6007f2890db1b..21118e3d822ae 100644 --- a/app/design/frontend/Magento/luma/Magento_Customer/email/account_new.html +++ b/app/design/frontend/Magento/luma/Magento_Customer/email/account_new.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml b/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml index 5d02aec14bedc..f21ed67177f3e 100644 --- a/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml +++ b/app/design/frontend/Magento/luma/Magento_Customer/layout/customer_account.xml @@ -1,7 +1,7 @@ @@ -13,26 +13,41 @@ Account Dashboardblock-collapsible-nav - + nav items - + Account Dashboard customer/account + 250 - + - Account Information - customer/account/edit + 200 - + Address Book customer/address + 190 + + + + + Account Information + customer/account/edit + 180 + + + + + 130 diff --git a/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml b/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml index bd1fd91d6d338..4d5bcb59dd2b8 100644 --- a/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml +++ b/app/design/frontend/Magento/luma/Magento_Customer/layout/default.xml @@ -1,7 +1,7 @@ @@ -9,7 +9,11 @@ - + + + 10 + + diff --git a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_email.less b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_email.less index c4876d40a5033..4eb58d149b548 100644 --- a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_email.less +++ b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_email.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less index 799094cf93d7c..a9b42a82036bc 100644 --- a/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Customer/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -106,6 +106,8 @@ .box-billing-address, .box-shipping-address, + .box-address-billing, + .box-address-shipping, .box-information, .box-newsletter { .box-content { @@ -319,6 +321,11 @@ .order-products-toolbar { position: relative; + + .toolbar-amount { + position: relative; + text-align: center; + } } } @@ -432,15 +439,23 @@ .block-addresses-list { .items.addresses { &:extend(.abs-add-clearfix-desktop all); + font-size: 0; > .item { - &:extend(.abs-blocks-2columns all); + display: inline-block; + font-size: @font-size__base; margin-bottom: @indent__base; + vertical-align: top; + width: 48%; &:nth-last-child(1), &:nth-last-child(2) { margin-bottom: 0; } + + &:nth-child(even) { + margin-left: 4%; + } } } @@ -474,6 +489,8 @@ .box-billing-address, .box-shipping-address, + .box-address-billing, + .box-address-shipping, .box-information { .box-content { &:extend(.abs-account-block-font-size all); diff --git a/app/design/frontend/Magento/luma/Magento_CustomerBalance/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_CustomerBalance/web/css/source/_module.less index f57fbf799a278..b6e0bcf92f46d 100644 --- a/app/design/frontend/Magento/luma/Magento_CustomerBalance/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_CustomerBalance/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Downloadable/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Downloadable/web/css/source/_module.less index 26d51bdd81c40..721eaa0472984 100644 --- a/app/design/frontend/Magento/luma/Magento_Downloadable/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Downloadable/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Email/email/footer.html b/app/design/frontend/Magento/luma/Magento_Email/email/footer.html index d6efc97c53076..f5ad1fbdc7b95 100644 --- a/app/design/frontend/Magento/luma/Magento_Email/email/footer.html +++ b/app/design/frontend/Magento/luma/Magento_Email/email/footer.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_GiftCard/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftCard/web/css/source/_module.less index 00043ac9fa89f..410a698a75fbf 100644 --- a/app/design/frontend/Magento/luma/Magento_GiftCard/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_GiftCard/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_GiftCardAccount/layout/checkout_cart_index.xml b/app/design/frontend/Magento/luma/Magento_GiftCardAccount/layout/checkout_cart_index.xml index dc8802e9efa22..24778720a0494 100644 --- a/app/design/frontend/Magento/luma/Magento_GiftCardAccount/layout/checkout_cart_index.xml +++ b/app/design/frontend/Magento/luma/Magento_GiftCardAccount/layout/checkout_cart_index.xml @@ -1,7 +1,7 @@ diff --git a/app/design/frontend/Magento/luma/Magento_GiftCardAccount/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftCardAccount/web/css/source/_module.less index a720365bdd34d..3e49911ddc3ac 100644 --- a/app/design/frontend/Magento/luma/Magento_GiftCardAccount/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_GiftCardAccount/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less index 6a579f19583c1..34a2cbea50dc3 100644 --- a/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_GiftMessage/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_GiftRegistry/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftRegistry/web/css/source/_module.less index cfcd464483543..966b64cb28f54 100644 --- a/app/design/frontend/Magento/luma/Magento_GiftRegistry/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_GiftRegistry/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less index 858beaefc7d94..b5096d1e6b425 100644 --- a/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_GiftWrapping/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_GroupedProduct/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_GroupedProduct/web/css/source/_module.less index 6c92bf54fa7fb..bf83dbd4c359c 100644 --- a/app/design/frontend/Magento/luma/Magento_GroupedProduct/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_GroupedProduct/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Invitation/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Invitation/web/css/source/_module.less index 8a7769fbc17b7..e06369dd8db50 100644 --- a/app/design/frontend/Magento/luma/Magento_Invitation/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Invitation/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_LayeredNavigation/templates/layer/state.phtml b/app/design/frontend/Magento/luma/Magento_LayeredNavigation/templates/layer/state.phtml index df76599f5693e..b6a180e146bcc 100644 --- a/app/design/frontend/Magento/luma/Magento_LayeredNavigation/templates/layer/state.phtml +++ b/app/design/frontend/Magento/luma/Magento_LayeredNavigation/templates/layer/state.phtml @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_new_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_new_guest.html index d1bd28deccad1..d3e6ad730c1ec 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_new_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_new_guest.html @@ -1,6 +1,6 @@ @@ -33,7 +33,7 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update.html b/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update.html index f308b02fc17f8..4e9e81d66a8a3 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update_guest.html index 7380a8ed7b94f..f5b9451f6e78d 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/creditmemo_update_guest.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new.html b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new.html index 259905d230d84..ea7493ad9889b 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new_guest.html index b92cc08c00421..93c9223f5adfd 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_new_guest.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update.html b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update.html index 348c512dd8a2d..e40fee4282cb7 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update_guest.html index cd79d1eaccd9b..a0fc2a0020512 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/invoice_update_guest.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html index 7dd84501b2e60..711af43f9b6fc 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html index 09a1131670f1f..c354d359fc27a 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/order_new_guest.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/order_update.html b/app/design/frontend/Magento/luma/Magento_Sales/email/order_update.html index fc40b2184eb68..3fe7f50888a3a 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/order_update.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/order_update.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/order_update_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/order_update_guest.html index c69f04e1d2dd5..65c727495ef1b 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/order_update_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/order_update_guest.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html index 643ff27dadc7c..986ed97cbe3e8 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html index f1fd2e8656f76..bc78443fa13bd 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_new_guest.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update.html b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update.html index b03a24e7d568b..22b3a80979eb2 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update_guest.html b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update_guest.html index d7c50f106f7d9..58a0402e32184 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update_guest.html +++ b/app/design/frontend/Magento/luma/Magento_Sales/email/shipment_update_guest.html @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less index 046cc354884f0..7627d44b76392 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less +++ b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less index 7cae8e74ae5c8..7131df8e00a01 100644 --- a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_SendFriend/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_SendFriend/web/css/source/_module.less index 1dd623e33de03..e5ee066079fbf 100644 --- a/app/design/frontend/Magento/luma/Magento_SendFriend/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_SendFriend/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml b/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml index 3c106cba41fbc..8a6fc51b5c17f 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml +++ b/app/design/frontend/Magento/luma/Magento_Theme/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml b/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml index 7f9b8c0619886..6b5d3cfbc2ceb 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml +++ b/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml @@ -1,7 +1,7 @@ diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less index 5581eb7fb0521..0c6dd928397ec 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -168,6 +168,11 @@ } } + .action-skip-wrapper { + height: 0; + position: relative; + } + // // Global notice // --------------------------------------------- diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less index 95c7ec15ebb33..d694e2c996187 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less +++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/module/_collapsible_navigation.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -13,6 +13,7 @@ @collapsible-nav-current-border-color: @color-orange-red1; @collapsible-nav-current-color: @color-black; @collapsible-nav-current-font-weight: @font-weight__semibold; +@collapsible-nav-delimiter__border-color: @color-gray82; @collapsible-nav-item-hover: @color-gray91; // @@ -64,6 +65,12 @@ .lib-css(border-color, @collapsible-nav-current-border-color); } } + + .delimiter { + border-top: 1px solid @collapsible-nav-delimiter__border-color; + display: block; + margin: @indent__s 1.8rem; + } } } } diff --git a/app/design/frontend/Magento/luma/Magento_Vault/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Vault/web/css/source/_module.less index 26352c1f550cd..7d098d0e4b57b 100644 --- a/app/design/frontend/Magento/luma/Magento_Vault/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Vault/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/Magento_Wishlist/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Wishlist/web/css/source/_module.less index 2e3820d3116ae..a08d66d57c4c3 100644 --- a/app/design/frontend/Magento/luma/Magento_Wishlist/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Wishlist/web/css/source/_module.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/composer.json b/app/design/frontend/Magento/luma/composer.json index 98fe0ebf8061c..97eb48f3c7e9e 100644 --- a/app/design/frontend/Magento/luma/composer.json +++ b/app/design/frontend/Magento/luma/composer.json @@ -2,7 +2,7 @@ "name": "magento/theme-frontend-luma", "description": "N/A", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/theme-frontend-blank": "100.2.*", "magento/framework": "100.2.*" }, diff --git a/app/design/frontend/Magento/luma/etc/view.xml b/app/design/frontend/Magento/luma/etc/view.xml index e0fc864e00084..8100eb4944527 100644 --- a/app/design/frontend/Magento/luma/etc/view.xml +++ b/app/design/frontend/Magento/luma/etc/view.xml @@ -1,7 +1,7 @@ @@ -77,10 +77,18 @@ 140 + + false + 700560 + + 700 + 700 + false + 88110 @@ -253,10 +261,7 @@ - true - - - true + prepend diff --git a/app/design/frontend/Magento/luma/registration.php b/app/design/frontend/Magento/luma/registration.php index 7bf3526379a43..4b6ddb9bf002f 100644 --- a/app/design/frontend/Magento/luma/registration.php +++ b/app/design/frontend/Magento/luma/registration.php @@ -1,6 +1,6 @@ diff --git a/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less b/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less index 877fc834f44fe..cd770e0f89c41 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less +++ b/app/design/frontend/Magento/luma/web/css/source/_actions-toolbar.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_breadcrumbs.less b/app/design/frontend/Magento/luma/web/css/source/_breadcrumbs.less index bc18583714276..67b661662222c 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_breadcrumbs.less +++ b/app/design/frontend/Magento/luma/web/css/source/_breadcrumbs.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_buttons.less b/app/design/frontend/Magento/luma/web/css/source/_buttons.less index 6f297953e9900..fca480e43ef0a 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_buttons.less +++ b/app/design/frontend/Magento/luma/web/css/source/_buttons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_email-extend.less b/app/design/frontend/Magento/luma/web/css/source/_email-extend.less index b3a56ce0ce801..65433e41fa492 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_email-extend.less +++ b/app/design/frontend/Magento/luma/web/css/source/_email-extend.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_email-variables.less b/app/design/frontend/Magento/luma/web/css/source/_email-variables.less index 969fe2594e236..a0ad2bfa2a769 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_email-variables.less +++ b/app/design/frontend/Magento/luma/web/css/source/_email-variables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_extends.less b/app/design/frontend/Magento/luma/web/css/source/_extends.less index 8b41c23851d30..317dd75996dbe 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_extends.less +++ b/app/design/frontend/Magento/luma/web/css/source/_extends.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_forms.less b/app/design/frontend/Magento/luma/web/css/source/_forms.less index 8d22eba9ca51f..3e6da23ab418e 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_forms.less +++ b/app/design/frontend/Magento/luma/web/css/source/_forms.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ @@ -113,10 +113,15 @@ .select-styling(); } + .field-error, div.mage-error[generated] { margin-top: 7px; } + .field-error { + .lib-form-validation-note(); + } + // TEMP .field .tooltip { diff --git a/app/design/frontend/Magento/luma/web/css/source/_pages.less b/app/design/frontend/Magento/luma/web/css/source/_pages.less index a7b8f7701f21e..febde1df7c3b8 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_pages.less +++ b/app/design/frontend/Magento/luma/web/css/source/_pages.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_popups.less b/app/design/frontend/Magento/luma/web/css/source/_popups.less index 5a4891d125b28..4f6f4e5fa536d 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_popups.less +++ b/app/design/frontend/Magento/luma/web/css/source/_popups.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_sections.less b/app/design/frontend/Magento/luma/web/css/source/_sections.less index d4cda1e0c7e1c..eccb2f7024bef 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_sections.less +++ b/app/design/frontend/Magento/luma/web/css/source/_sections.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_tables.less b/app/design/frontend/Magento/luma/web/css/source/_tables.less index 273f085454da9..b1c32c0dca3d7 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_tables.less +++ b/app/design/frontend/Magento/luma/web/css/source/_tables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_theme.less b/app/design/frontend/Magento/luma/web/css/source/_theme.less index 4a867fee19b2c..4a56e4814af9f 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_theme.less +++ b/app/design/frontend/Magento/luma/web/css/source/_theme.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/_variables.less b/app/design/frontend/Magento/luma/web/css/source/_variables.less index 446acc03bb451..e199f28b15d8f 100644 --- a/app/design/frontend/Magento/luma/web/css/source/_variables.less +++ b/app/design/frontend/Magento/luma/web/css/source/_variables.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less b/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less index edc0a0a1b83d0..8470c4d20514a 100644 --- a/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less +++ b/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/app/etc/NonComposerComponentRegistration.php b/app/etc/NonComposerComponentRegistration.php index bd3289dc5f742..8fba26490d511 100755 --- a/app/etc/NonComposerComponentRegistration.php +++ b/app/etc/NonComposerComponentRegistration.php @@ -1,6 +1,6 @@ @@ -18,6 +18,8 @@ + + @@ -103,6 +105,7 @@ + @@ -154,7 +157,14 @@ + + + + + Magento\Framework\Acl\Builder\Proxy + + Magento\Framework\Filesystem\Driver\File @@ -432,7 +442,7 @@ - Magento\Framework\Data\CollectionDataSourceInterface + Magento\Framework\View\Element\Block\ArgumentInterface @@ -955,11 +965,6 @@ Magento\Framework\View\Design\Theme\Image\Uploader\Proxy - - - Magento\Framework\App\Cache\Type\Config - - Magento\Framework\App\Config\Initial\Reader\Proxy @@ -1205,7 +1210,6 @@ Magento\Framework\EntityManager\Mapper - Magento\Framework\EntityManager\CustomAttributesMapper @@ -1219,4 +1223,24 @@ + + + + Magento\Framework\DB\Select\InQueryModifier + + + + + + + HASH + BTREE + + + INNODB + MEMORY + MYISAM + + + diff --git a/app/functions.php b/app/functions.php index 78eef9b883663..954cb531b4ddc 100644 --- a/app/functions.php +++ b/app/functions.php @@ -1,6 +1,6 @@ diff --git a/app/i18n/Magento/de_DE/registration.php b/app/i18n/Magento/de_DE/registration.php index fb69a0e0afe25..432284dc5bc3e 100644 --- a/app/i18n/Magento/de_DE/registration.php +++ b/app/i18n/Magento/de_DE/registration.php @@ -1,6 +1,6 @@ diff --git a/app/i18n/Magento/en_US/registration.php b/app/i18n/Magento/en_US/registration.php index e2f5982f8a2b1..97e84e3132d13 100644 --- a/app/i18n/Magento/en_US/registration.php +++ b/app/i18n/Magento/en_US/registration.php @@ -1,6 +1,6 @@ diff --git a/app/i18n/Magento/es_ES/registration.php b/app/i18n/Magento/es_ES/registration.php index 560a0d6bb633d..a3876665febb6 100644 --- a/app/i18n/Magento/es_ES/registration.php +++ b/app/i18n/Magento/es_ES/registration.php @@ -1,6 +1,6 @@ diff --git a/app/i18n/Magento/fr_FR/registration.php b/app/i18n/Magento/fr_FR/registration.php index fd2a310434a7c..ef2018c1a2401 100644 --- a/app/i18n/Magento/fr_FR/registration.php +++ b/app/i18n/Magento/fr_FR/registration.php @@ -1,6 +1,6 @@ diff --git a/app/i18n/Magento/nl_NL/registration.php b/app/i18n/Magento/nl_NL/registration.php index 3959562a1a4db..1a23b26871d7f 100644 --- a/app/i18n/Magento/nl_NL/registration.php +++ b/app/i18n/Magento/nl_NL/registration.php @@ -1,6 +1,6 @@ diff --git a/app/i18n/Magento/pt_BR/registration.php b/app/i18n/Magento/pt_BR/registration.php index a14fc0b8cb28e..5970863cd6326 100644 --- a/app/i18n/Magento/pt_BR/registration.php +++ b/app/i18n/Magento/pt_BR/registration.php @@ -1,6 +1,6 @@ diff --git a/app/i18n/Magento/zh_Hans_CN/registration.php b/app/i18n/Magento/zh_Hans_CN/registration.php index ec58f71f8ed16..7609eb99e8a58 100644 --- a/app/i18n/Magento/zh_Hans_CN/registration.php +++ b/app/i18n/Magento/zh_Hans_CN/registration.php @@ -1,6 +1,6 @@ getPrevious(); } - exit(Cli::RETURN_FAILURE); + exit(Magento\Framework\Console\Cli::RETURN_FAILURE); } diff --git a/composer.json b/composer.json index 8053b76a01a22..3818ec644cba1 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "AFL-3.0" ], "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "zendframework/zend-stdlib": "~2.4.6", "zendframework/zend-code": "~2.4.6", "zendframework/zend-server": "~2.4.6", @@ -31,24 +31,24 @@ "zendframework/zend-serializer": "~2.4.6", "zendframework/zend-log": "~2.4.6", "zendframework/zend-http": "~2.4.6", - "magento/zendframework1": "1.12.16", + "magento/zendframework1": "~1.12.16", "colinmollenhour/credis": "1.6", - "colinmollenhour/php-redis-session-abstract": "1.1", + "colinmollenhour/php-redis-session-abstract": "1.2", "colinmollenhour/cache-backend-redis": "1.9", "colinmollenhour/cache-backend-file": "1.4", "composer/composer": "1.0.0-beta1", - "monolog/monolog": "1.16.0", + "monolog/monolog": "^1.17", "oyejorge/less.php": "~1.7.0", "pelago/emogrifier": "0.1.1", "tubalmartin/cssmin": "2.4.8-p4", "magento/magento-composer-installer": ">=0.1.11", "braintree/braintree_php": "3.7.0", - "symfony/console": "~2.3 <2.7", + "symfony/console": "~2.3, !=2.7.0", "symfony/event-dispatcher": "~2.1", "symfony/process": "~2.1", "phpseclib/phpseclib": "2.0.*", "tedivm/jshrink": "~1.0.1", - "magento/composer": "~1.0.0", + "magento/composer": "~1.1.0", "lib-libxml": "*", "ext-ctype": "*", "ext-gd": "*", @@ -64,6 +64,7 @@ "ext-mbstring": "*", "ext-openssl": "*", "ext-zip": "*", + "ext-pdo_mysql": "*", "sjparkinson/static-review": "~4.1", "ramsey/uuid": "3.4" }, @@ -71,8 +72,8 @@ "phpunit/phpunit": "4.1.0", "squizlabs/php_codesniffer": "1.5.3", "phpmd/phpmd": "@stable", - "pdepend/pdepend": "2.2.2", - "fabpot/php-cs-fixer": "~1.2", + "pdepend/pdepend": "2.4.0", + "friendsofphp/php-cs-fixer": "~1.2", "lusitanian/oauth": "~0.3 <=0.7.0", "sebastian/phpcpd": "2.0.0" }, @@ -80,6 +81,7 @@ "magento/module-marketplace": "100.2.0-dev", "magento/module-admin-notification": "100.2.0-dev", "magento/module-advanced-pricing-import-export": "100.2.0-dev", + "magento/module-analytics": "100.2.0-dev", "magento/module-authorization": "100.2.0-dev", "magento/module-authorizenet": "100.2.0-dev", "magento/module-backend": "100.2.0-dev", @@ -150,6 +152,7 @@ "magento/module-rss": "100.2.0-dev", "magento/module-rule": "100.2.0-dev", "magento/module-sales": "100.2.0-dev", + "magento/module-sales-inventory": "100.2.0-dev", "magento/module-sales-rule": "100.2.0-dev", "magento/module-sales-sequence": "100.2.0-dev", "magento/module-sample-data": "100.2.0-dev", @@ -215,9 +218,6 @@ "tinymce/tinymce": "lib/web/tiny_mce" } }, - "config": { - "use-include-path": true - }, "autoload": { "psr-4": { "Magento\\Framework\\": "lib/internal/Magento/Framework/", @@ -225,10 +225,18 @@ "Magento\\": "app/code/Magento/" }, "psr-0": { - "": "app/code/" + "": [ + "app/code/", + "generated/code" + ] }, "files": [ "app/etc/NonComposerComponentRegistration.php" + ], + "exclude-from-classmap": [ + "**/dev/**", + "**/update/**", + "**/Test/**" ] }, "autoload-dev": { diff --git a/composer.lock b/composer.lock index 6fd73ef405c82..5574f5211c642 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "ad3de2234f78fd4b353ae6a1b22401fc", - "content-hash": "25dcf96ed1d8b12a25111e8b3af61317", + "hash": "ce5a9b438108d958029ff640047ce7e6", + "content-hash": "e79bcacd835ffe597a53ea3ba407e928", "packages": [ { "name": "braintree/braintree_php", @@ -167,21 +167,21 @@ }, { "name": "colinmollenhour/php-redis-session-abstract", - "version": "v1.1", + "version": "v1.2", "source": { "type": "git", "url": "https://github.com/colinmollenhour/php-redis-session-abstract.git", - "reference": "95330b7f29663dab81f53d1a438e4d927b6c5f66" + "reference": "2b552c9bbe06967329dd41e1bd3e0aed02313ddb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/php-redis-session-abstract/zipball/95330b7f29663dab81f53d1a438e4d927b6c5f66", - "reference": "95330b7f29663dab81f53d1a438e4d927b6c5f66", + "url": "https://api.github.com/repos/colinmollenhour/php-redis-session-abstract/zipball/2b552c9bbe06967329dd41e1bd3e0aed02313ddb", + "reference": "2b552c9bbe06967329dd41e1bd3e0aed02313ddb", "shasum": "" }, "require": { "colinmollenhour/credis": "1.6", - "magento/zendframework1": "1.12.16", + "magento/zendframework1": "~1.12.0", "php": "~5.5.0|~5.6.0|~7.0.0" }, "type": "library", @@ -201,7 +201,7 @@ ], "description": "A Redis-based session handler with optimistic locking", "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", - "time": "2016-02-03 18:13:49" + "time": "2016-08-04 18:05:51" }, { "name": "composer/composer", @@ -280,16 +280,16 @@ }, { "name": "composer/semver", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98" + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", - "reference": "03c9de5aa25e7672c4ad251eeaba0c47a06c8b98", + "url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573", + "reference": "c7cb9a2095a074d131b65a8a0cd294479d785573", "shasum": "" }, "require": { @@ -338,20 +338,20 @@ "validation", "versioning" ], - "time": "2016-06-02 09:04:51" + "time": "2016-08-30 16:08:34" }, { "name": "composer/spdx-licenses", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88" + "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/88c26372b1afac36d8db601cdf04ad8716f53d88", - "reference": "88c26372b1afac36d8db601cdf04ad8716f53d88", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/96c6a07b05b716e89a44529d060bc7f5c263cb13", + "reference": "96c6a07b05b716e89a44529d060bc7f5c263cb13", "shasum": "" }, "require": { @@ -399,7 +399,7 @@ "spdx", "validator" ], - "time": "2016-05-04 12:27:30" + "time": "2016-09-28 07:17:45" }, { "name": "justinrainbow/json-schema", @@ -518,22 +518,22 @@ }, { "name": "magento/composer", - "version": "1.0.3", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/magento/composer.git", - "reference": "b53f7c8a037860b467083e94de7c17cfd323e365" + "reference": "13eee8c93b27d4cea5562d449be4a4cc7a0867d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/composer/zipball/b53f7c8a037860b467083e94de7c17cfd323e365", - "reference": "b53f7c8a037860b467083e94de7c17cfd323e365", + "url": "https://api.github.com/repos/magento/composer/zipball/13eee8c93b27d4cea5562d449be4a4cc7a0867d2", + "reference": "13eee8c93b27d4cea5562d449be4a4cc7a0867d2", "shasum": "" }, "require": { "composer/composer": "1.0.0-beta1", "php": "~5.5.0|~5.6.0|~7.0.0", - "symfony/console": "~2.3 <2.7" + "symfony/console": "~2.3, !=2.7.0" }, "require-dev": { "phpunit/phpunit": "4.1.0" @@ -550,20 +550,20 @@ "AFL-3.0" ], "description": "Magento composer library helps to instantiate Composer application and run composer commands.", - "time": "2016-03-08 20:50:51" + "time": "2017-02-07 21:59:01" }, { "name": "magento/magento-composer-installer", - "version": "0.1.11", + "version": "0.1.12", "source": { "type": "git", "url": "https://github.com/magento/magento-composer-installer.git", - "reference": "a12b9577cd9859af67d2365ae38d23ddfc57cf4d" + "reference": "10c600e88ad34fec71bb6b435ea8415ce92d51de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/magento-composer-installer/zipball/a12b9577cd9859af67d2365ae38d23ddfc57cf4d", - "reference": "a12b9577cd9859af67d2365ae38d23ddfc57cf4d", + "url": "https://api.github.com/repos/magento/magento-composer-installer/zipball/10c600e88ad34fec71bb6b435ea8415ce92d51de", + "reference": "10c600e88ad34fec71bb6b435ea8415ce92d51de", "shasum": "" }, "require": { @@ -629,20 +629,20 @@ "composer-installer", "magento" ], - "time": "2016-06-15 04:02:25" + "time": "2016-10-06 16:05:07" }, { "name": "magento/zendframework1", - "version": "1.12.16", + "version": "1.12.16-patch2", "source": { "type": "git", "url": "https://github.com/magento/zf1.git", - "reference": "c9d607bfd9454bc18b9deff737ccd5d044e2ab10" + "reference": "6a4cbd21245ad1854d17cccde542acd70ebdfb9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/zf1/zipball/c9d607bfd9454bc18b9deff737ccd5d044e2ab10", - "reference": "c9d607bfd9454bc18b9deff737ccd5d044e2ab10", + "url": "https://api.github.com/repos/magento/zf1/zipball/6a4cbd21245ad1854d17cccde542acd70ebdfb9c", + "reference": "6a4cbd21245ad1854d17cccde542acd70ebdfb9c", "shasum": "" }, "require": { @@ -676,20 +676,20 @@ "ZF1", "framework" ], - "time": "2015-10-29 14:34:55" + "time": "2017-01-17 16:40:08" }, { "name": "monolog/monolog", - "version": "1.16.0", + "version": "1.22.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "c0c0b4bee3aabce7182876b0d912ef2595563db7" + "reference": "bad29cb8d18ab0315e6c477751418a82c850d558" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c0c0b4bee3aabce7182876b0d912ef2595563db7", - "reference": "c0c0b4bee3aabce7182876b0d912ef2595563db7", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bad29cb8d18ab0315e6c477751418a82c850d558", + "reference": "bad29cb8d18ab0315e6c477751418a82c850d558", "shasum": "" }, "require": { @@ -700,16 +700,17 @@ "psr/log-implementation": "1.0.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9", + "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", + "jakub-onderka/php-parallel-lint": "0.9", + "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", "phpunit/phpunit": "~4.5", "phpunit/phpunit-mock-objects": "2.3.0", - "raven/raven": "~0.8", "ruflin/elastica": ">=0.90 <3.0", - "swiftmailer/swiftmailer": "~5.3", - "videlalvaro/php-amqplib": "~2.4" + "sentry/sentry": "^0.13", + "swiftmailer/swiftmailer": "~5.3" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", @@ -717,16 +718,17 @@ "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", "ext-mongo": "Allow sending log messages to a MongoDB server", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", - "raven/raven": "Allow sending log messages to a Sentry server", "rollbar/rollbar": "Allow sending log messages to Rollbar", "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib" + "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.16.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -752,7 +754,7 @@ "logging", "psr-3" ], - "time": "2015-08-09 17:44:44" + "time": "2016-11-26 00:15:39" }, { "name": "oyejorge/less.php", @@ -818,16 +820,16 @@ }, { "name": "paragonie/random_compat", - "version": "v2.0.2", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf" + "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf", - "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", + "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", "shasum": "" }, "require": { @@ -862,7 +864,7 @@ "pseudorandom", "random" ], - "time": "2016-04-03 06:00:07" + "time": "2016-11-07 23:38:38" }, { "name": "pelago/emogrifier", @@ -922,16 +924,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370" + "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/41f85e9c2582b3f6d1b7d20395fb40c687ad5370", - "reference": "41f85e9c2582b3f6d1b7d20395fb40c687ad5370", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/ab8028c93c03cc8d9c824efa75dc94f1db2369bf", + "reference": "ab8028c93c03cc8d9c824efa75dc94f1db2369bf", "shasum": "" }, "require": { @@ -1010,26 +1012,34 @@ "x.509", "x509" ], - "time": "2016-08-18 18:49:14" + "time": "2016-10-04 00:57:04" }, { "name": "psr/log", - "version": "1.0.0", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "shasum": "" }, + "require": { + "php": ">=5.3.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "psr-0": { - "Psr\\Log\\": "" + "psr-4": { + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1043,12 +1053,13 @@ } ], "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ "log", "psr", "psr-3" ], - "time": "2012-12-21 11:40:51" + "time": "2016-10-10 12:19:37" }, { "name": "ramsey/uuid", @@ -1180,16 +1191,16 @@ }, { "name": "seld/jsonlint", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "66834d3e3566bb5798db7294619388786ae99394" + "reference": "19495c181d6d53a0a13414154e52817e3b504189" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", - "reference": "66834d3e3566bb5798db7294619388786ae99394", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/19495c181d6d53a0a13414154e52817e3b504189", + "reference": "19495c181d6d53a0a13414154e52817e3b504189", "shasum": "" }, "require": { @@ -1222,7 +1233,7 @@ "parser", "validator" ], - "time": "2015-11-21 02:21:41" + "time": "2016-11-14 17:59:58" }, { "name": "seld/phar-utils", @@ -1323,27 +1334,27 @@ }, { "name": "symfony/console", - "version": "v2.6.13", - "target-dir": "Symfony/Component/Console", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359" + "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0e5e18ae09d3f5c06367759be940e9ed3f568359", - "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359", + "url": "https://api.github.com/repos/symfony/console/zipball/f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4", + "reference": "f3c234cd8db9f7e520a91d695db7d8bb5daeb7a4", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9", + "symfony/debug": "~2.7,>=2.7.2|~3.0.0", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.1", - "symfony/phpunit-bridge": "~2.7", - "symfony/process": "~2.1" + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" }, "suggest": { "psr/log": "For using the console logger", @@ -1353,13 +1364,16 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev" + "dev-master": "2.8-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\Console\\": "" - } + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1377,20 +1391,77 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2015-07-26 09:08:40" + "time": "2017-02-06 12:04:06" + }, + { + "name": "symfony/debug", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2016-07-30 07:22:48" }, { "name": "symfony/event-dispatcher", - "version": "v2.8.9", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8" + "reference": "74877977f90fb9c3e46378d5764217c55f32df34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/889983a79a043dfda68f38c38b6dba092dd49cd8", - "reference": "889983a79a043dfda68f38c38b6dba092dd49cd8", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/74877977f90fb9c3e46378d5764217c55f32df34", + "reference": "74877977f90fb9c3e46378d5764217c55f32df34", "shasum": "" }, "require": { @@ -1437,29 +1508,29 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2016-07-28 16:56:28" + "time": "2017-01-02 20:30:24" }, { "name": "symfony/filesystem", - "version": "v2.8.9", + "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd" + "reference": "a0c6ef2dc78d33b58d91d3a49f49797a184d06f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/ab4c3f085c8f5a56536845bf985c4cef30bf75fd", - "reference": "ab4c3f085c8f5a56536845bf985c4cef30bf75fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/a0c6ef2dc78d33b58d91d3a49f49797a184d06f4", + "reference": "a0c6ef2dc78d33b58d91d3a49f49797a184d06f4", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.5.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -1486,20 +1557,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2016-07-20 05:41:28" + "time": "2017-01-08 20:47:33" }, { "name": "symfony/finder", - "version": "v3.1.3", + "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7" + "reference": "8c71141cae8e2957946b403cc71a67213c0380d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/8201978de88a9fa0923e18601bb17f1df9c721e7", - "reference": "8201978de88a9fa0923e18601bb17f1df9c721e7", + "url": "https://api.github.com/repos/symfony/finder/zipball/8c71141cae8e2957946b403cc71a67213c0380d6", + "reference": "8c71141cae8e2957946b403cc71a67213c0380d6", "shasum": "" }, "require": { @@ -1508,7 +1579,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -1535,20 +1606,79 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "time": "2017-01-02 20:32:22" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-11-14 01:06:16" }, { "name": "symfony/process", - "version": "v2.8.9", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c" + "reference": "0110ac49348d14eced7d3278ea7485f22196932e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d20332e43e8774ff8870b394f3dd6020cc7f8e0c", - "reference": "d20332e43e8774ff8870b394f3dd6020cc7f8e0c", + "url": "https://api.github.com/repos/symfony/process/zipball/0110ac49348d14eced7d3278ea7485f22196932e", + "reference": "0110ac49348d14eced7d3278ea7485f22196932e", "shasum": "" }, "require": { @@ -1584,7 +1714,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-07-28 11:13:19" + "time": "2017-02-03 12:08:06" }, { "name": "tedivm/jshrink", @@ -1678,7 +1808,7 @@ }, { "name": "zendframework/zend-code", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-code.git", @@ -1731,7 +1861,7 @@ }, { "name": "zendframework/zend-config", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-config.git", @@ -1788,7 +1918,7 @@ }, { "name": "zendframework/zend-console", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-console.git", @@ -1838,7 +1968,7 @@ }, { "name": "zendframework/zend-crypt", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-crypt.git", @@ -1890,7 +2020,7 @@ }, { "name": "zendframework/zend-di", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-di.git", @@ -1941,7 +2071,7 @@ }, { "name": "zendframework/zend-escaper", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-escaper.git", @@ -1986,7 +2116,7 @@ }, { "name": "zendframework/zend-eventmanager", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-eventmanager.git", @@ -2032,7 +2162,7 @@ }, { "name": "zendframework/zend-filter", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-filter.git", @@ -2088,7 +2218,7 @@ }, { "name": "zendframework/zend-form", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-form.git", @@ -2159,7 +2289,7 @@ }, { "name": "zendframework/zend-http", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-http.git", @@ -2210,7 +2340,7 @@ }, { "name": "zendframework/zend-i18n", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-i18n.git", @@ -2274,7 +2404,7 @@ }, { "name": "zendframework/zend-inputfilter", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-inputfilter.git", @@ -2325,7 +2455,7 @@ }, { "name": "zendframework/zend-json", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-json.git", @@ -2379,7 +2509,7 @@ }, { "name": "zendframework/zend-loader", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-loader.git", @@ -2424,7 +2554,7 @@ }, { "name": "zendframework/zend-log", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-log.git", @@ -2486,7 +2616,7 @@ }, { "name": "zendframework/zend-math", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-math.git", @@ -2537,7 +2667,7 @@ }, { "name": "zendframework/zend-modulemanager", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-modulemanager.git", @@ -2595,7 +2725,7 @@ }, { "name": "zendframework/zend-mvc", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-mvc.git", @@ -2683,7 +2813,7 @@ }, { "name": "zendframework/zend-serializer", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-serializer.git", @@ -2736,7 +2866,7 @@ }, { "name": "zendframework/zend-server", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-server.git", @@ -2783,7 +2913,7 @@ }, { "name": "zendframework/zend-servicemanager", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-servicemanager.git", @@ -2833,7 +2963,7 @@ }, { "name": "zendframework/zend-soap", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-soap.git", @@ -2885,7 +3015,7 @@ }, { "name": "zendframework/zend-stdlib", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-stdlib.git", @@ -2940,7 +3070,7 @@ }, { "name": "zendframework/zend-text", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-text.git", @@ -2987,7 +3117,7 @@ }, { "name": "zendframework/zend-uri", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-uri.git", @@ -3035,7 +3165,7 @@ }, { "name": "zendframework/zend-validator", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-validator.git", @@ -3100,7 +3230,7 @@ }, { "name": "zendframework/zend-view", - "version": "2.4.10", + "version": "2.4.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-view.git", @@ -3232,17 +3362,17 @@ "time": "2015-06-14 21:17:01" }, { - "name": "fabpot/php-cs-fixer", - "version": "v1.12.0", + "name": "friendsofphp/php-cs-fixer", + "version": "v1.13.1", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "ddac737e1c06a310a0bb4b3da755a094a31a916a" + "reference": "0ea4f7ed06ca55da1d8fc45da26ff87f261c4088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/ddac737e1c06a310a0bb4b3da755a094a31a916a", - "reference": "ddac737e1c06a310a0bb4b3da755a094a31a916a", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/0ea4f7ed06ca55da1d8fc45da26ff87f261c4088", + "reference": "0ea4f7ed06ca55da1d8fc45da26ff87f261c4088", "shasum": "" }, "require": { @@ -3287,8 +3417,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "abandoned": "friendsofphp/php-cs-fixer", - "time": "2016-08-17 00:17:27" + "time": "2016-12-01 00:05:05" }, { "name": "lusitanian/oauth", @@ -3359,26 +3488,26 @@ }, { "name": "pdepend/pdepend", - "version": "2.2.2", + "version": "2.4.0", "source": { "type": "git", "url": "https://github.com/pdepend/pdepend.git", - "reference": "d3ae0d084d526cdc6c3f1b858fb7148de77b41c5" + "reference": "64ba7e6d0507729e2bb482cf20cd12c4d96d99bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/d3ae0d084d526cdc6c3f1b858fb7148de77b41c5", - "reference": "d3ae0d084d526cdc6c3f1b858fb7148de77b41c5", + "url": "https://api.github.com/repos/pdepend/pdepend/zipball/64ba7e6d0507729e2bb482cf20cd12c4d96d99bc", + "reference": "64ba7e6d0507729e2bb482cf20cd12c4d96d99bc", "shasum": "" }, "require": { "php": ">=5.3.7", - "symfony/config": "^2.3.0", - "symfony/dependency-injection": "^2.3.0", - "symfony/filesystem": "^2.3.0" + "symfony/config": "^2.3.0|^3", + "symfony/dependency-injection": "^2.3.0|^3", + "symfony/filesystem": "^2.3.0|^3" }, "require-dev": { - "phpunit/phpunit": "^4.0.0,<4.8", + "phpunit/phpunit": "^4.4.0,<4.8", "squizlabs/php_codesniffer": "^2.0.0" }, "bin": [ @@ -3386,8 +3515,8 @@ ], "type": "library", "autoload": { - "psr-0": { - "PDepend\\": "src/main/php/" + "psr-4": { + "PDepend\\": "src/main/php/PDepend" } }, "notification-url": "https://packagist.org/downloads/", @@ -3395,25 +3524,25 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2015-10-16 08:49:58" + "time": "2017-01-10 13:45:16" }, { "name": "phpmd/phpmd", - "version": "2.4.3", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/phpmd/phpmd.git", - "reference": "2b9c2417a18696dfb578b38c116cd0ddc19b256e" + "reference": "9298602a922cd8c46666df8d540a60bc5925ce55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/2b9c2417a18696dfb578b38c116cd0ddc19b256e", - "reference": "2b9c2417a18696dfb578b38c116cd0ddc19b256e", + "url": "https://api.github.com/repos/phpmd/phpmd/zipball/9298602a922cd8c46666df8d540a60bc5925ce55", + "reference": "9298602a922cd8c46666df8d540a60bc5925ce55", "shasum": "" }, "require": { "pdepend/pdepend": "^2.0.4", - "php": ">=5.3.0" + "php": ">=5.3.9" }, "require-dev": { "phpunit/phpunit": "^4.0", @@ -3460,7 +3589,7 @@ "phpmd", "pmd" ], - "time": "2016-04-04 11:52:04" + "time": "2016-11-23 20:33:32" }, { "name": "phpunit/php-code-coverage", @@ -3656,16 +3785,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.4.8", + "version": "1.4.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b", + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b", "shasum": "" }, "require": { @@ -3701,7 +3830,7 @@ "keywords": [ "tokenizer" ], - "time": "2015-09-15 10:49:45" + "time": "2016-11-15 14:06:22" }, { "name": "phpunit/phpunit", @@ -3835,22 +3964,22 @@ }, { "name": "sebastian/comparator", - "version": "1.2.0", + "version": "1.2.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", "shasum": "" }, "require": { "php": ">=5.3.3", "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" + "sebastian/exporter": "~1.2 || ~2.0" }, "require-dev": { "phpunit/phpunit": "~4.4" @@ -3895,7 +4024,7 @@ "compare", "equality" ], - "time": "2015-07-26 15:48:44" + "time": "2017-01-29 09:50:25" }, { "name": "sebastian/diff", @@ -4321,21 +4450,24 @@ }, { "name": "symfony/config", - "version": "v2.8.9", + "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4" + "reference": "2ffa7b84d647b8be1788d46b44e438cb3d62056c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/4275ef5b59f18959df0eee3991e9ca0cc208ffd4", - "reference": "4275ef5b59f18959df0eee3991e9ca0cc208ffd4", + "url": "https://api.github.com/repos/symfony/config/zipball/2ffa7b84d647b8be1788d46b44e438cb3d62056c", + "reference": "2ffa7b84d647b8be1788d46b44e438cb3d62056c", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/filesystem": "~2.3|~3.0.0" + "php": ">=5.5.9", + "symfony/filesystem": "~2.8|~3.0" + }, + "require-dev": { + "symfony/yaml": "~3.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -4343,7 +4475,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -4370,32 +4502,29 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2016-07-26 08:02:44" + "time": "2017-02-06 12:04:21" }, { "name": "symfony/dependency-injection", - "version": "v2.8.9", + "version": "v3.1.10", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12" + "reference": "f4a04433f82eb8ca58555d1b6375293fc7c90d18" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f2b5a00d176f6a201dc430375c0ef37706ea3d12", - "reference": "f2b5a00d176f6a201dc430375c0ef37706ea3d12", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f4a04433f82eb8ca58555d1b6375293fc7c90d18", + "reference": "f4a04433f82eb8ca58555d1b6375293fc7c90d18", "shasum": "" }, "require": { - "php": ">=5.3.9" - }, - "conflict": { - "symfony/expression-language": "<2.6" + "php": ">=5.5.9" }, "require-dev": { - "symfony/config": "~2.2|~3.0.0", - "symfony/expression-language": "~2.6|~3.0.0", - "symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7" + "symfony/config": "~2.8|~3.0", + "symfony/expression-language": "~2.8|~3.0", + "symfony/yaml": "~2.8.7|~3.0.7|~3.1.1|~3.2" }, "suggest": { "symfony/config": "", @@ -4406,7 +4535,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -4433,20 +4562,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:20:35" + "time": "2017-01-28 00:04:57" }, { "name": "symfony/stopwatch", - "version": "v3.1.3", + "version": "v3.2.3", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1" + "reference": "9aa0b51889c01bca474853ef76e9394b02264464" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/bb42806b12c5f89db4ebf64af6741afe6d8457e1", - "reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/9aa0b51889c01bca474853ef76e9394b02264464", + "reference": "9aa0b51889c01bca474853ef76e9394b02264464", "shasum": "" }, "require": { @@ -4455,7 +4584,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -4482,20 +4611,20 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "time": "2017-01-02 20:32:22" }, { "name": "symfony/yaml", - "version": "v2.8.9", + "version": "v2.8.17", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d" + "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0ceab136f43ed9d3e97b3eea32a7855dc50c121d", - "reference": "0ceab136f43ed9d3e97b3eea32a7855dc50c121d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/322a8c2dfbca15ad6b1b27e182899f98ec0e0153", + "reference": "322a8c2dfbca15ad6b1b27e182899f98ec0e0153", "shasum": "" }, "require": { @@ -4531,7 +4660,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-07-17 09:06:15" + "time": "2017-01-21 16:40:50" }, { "name": "theseer/fdomdocument", @@ -4582,7 +4711,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "lib-libxml": "*", "ext-ctype": "*", "ext-gd": "*", @@ -4597,7 +4726,8 @@ "ext-xsl": "*", "ext-mbstring": "*", "ext-openssl": "*", - "ext-zip": "*" + "ext-zip": "*", + "ext-pdo_mysql": "*" }, "platform-dev": [] } diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester.php b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester.php index b381eddfb6086..72eac98d10e48 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester.php +++ b/dev/tests/api-functional/_files/Magento/TestModule1/Controller/CookieTester.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/di.xml index d45be6bf49c25..6d9f884c26220 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/di.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/extension_attributes.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/extension_attributes.xml index 0afbc34780a24..15f7911132899 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/extension_attributes.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/frontend/routes.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/frontend/routes.xml index 68f1fe89373a7..4a369bb927322 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/frontend/routes.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/frontend/routes.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml index 8cf4128be3aaf..c582b1a8984e1 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml index 7ca2ac77cde68..e8585336bcc29 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/registration.php b/dev/tests/api-functional/_files/Magento/TestModule1/registration.php index d51ed6916e49d..afadfab05949c 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModule1/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/di.xml index c135b27bf5988..e8818d3536474 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/etc/di.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml index 6fd21222ca19f..fbb1d97de2d6c 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/AllSoapNoRestV1.xsd b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/AllSoapNoRestV1.xsd index 8f731dbadf493..d778e39ad0fce 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/AllSoapNoRestV1.xsd +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/AllSoapNoRestV1.xsd @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/NoWebApiXmlV1.xsd b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/NoWebApiXmlV1.xsd index 8f731dbadf493..d778e39ad0fce 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/NoWebApiXmlV1.xsd +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/NoWebApiXmlV1.xsd @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/SubsetRestV1.xsd b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/SubsetRestV1.xsd index 8f731dbadf493..d778e39ad0fce 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/SubsetRestV1.xsd +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/schema/SubsetRestV1.xsd @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/webapi.xml index 0c1f57b64275a..001af9d3e3641 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/registration.php b/dev/tests/api-functional/_files/Magento/TestModule2/registration.php index a250e2afe2137..a94b6b09ca136 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModule2/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/di.xml index d47e8c1d058da..75196a4a0731d 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule3/etc/di.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml index 2231cfe549656..abd14d4eafde5 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/webapi.xml index a43add9fd1309..fee7ca16dd8cc 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule3/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/registration.php b/dev/tests/api-functional/_files/Magento/TestModule3/registration.php index 2b5d3b62ac115..adaca36122ef9 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule3/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModule3/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/di.xml index 893699af99e41..a5c0588995e6c 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule4/etc/di.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml index ade672c46a81f..7cc10b8831053 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/webapi.xml index 00c75d8819e18..cec28d3f9c24e 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule4/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/registration.php b/dev/tests/api-functional/_files/Magento/TestModule4/registration.php index 52d1226ed38c4..1d3e53715aad5 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule4/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModule4/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/di.xml index dbcad57732107..759d6e3d69a61 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/etc/di.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml index efb6231e39eda..1d41e1edffe4d 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/webapi.xml index 7604ac2989dd5..7404d83dea92a 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/registration.php b/dev/tests/api-functional/_files/Magento/TestModule5/registration.php index 7dcd22c3ce36d..f60cb992f6b7a 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModule5/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/extension_attributes.xml b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/extension_attributes.xml index 0db1fac43ca1f..75b915f373f4b 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/extension_attributes.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/webapi.xml index 6d35defe7126c..5b1213fd4b83c 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/webapi.xml @@ -1,7 +1,7 @@ @@ -31,4 +31,4 @@ - \ No newline at end of file + diff --git a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/registration.php b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/registration.php index d2cbe65af6d03..c29d9cd4e6113 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml index b491d8c6fd114..b0e4cc9851f02 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/registration.php b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/registration.php index b88618bcad42d..c1b3e90f38451 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/di.xml index 0d05979bb9a28..9753ede9303f8 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/di.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml index 7025e867eb4ff..619a9c8ed5d1e 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml index f97598fb811d9..ce77a096b1988 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/webapi.xml index 35abb11d2ed3e..6de3cd6c74020 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/registration.php b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/registration.php index f311ea6441c4a..b93ed995fcc14 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/di.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/di.xml index bab86322a5de1..ceb0ea2d6600e 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/di.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/extension_attributes.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/extension_attributes.xml index d7edb7095d42e..215e4b0d21cc9 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/extension_attributes.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml index 133fe51a377ff..02cfca05d88cf 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/webapi.xml index 9aa31d65c53d0..3233dd47b521a 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/registration.php b/dev/tests/api-functional/_files/Magento/TestModuleMSC/registration.php index 4047295b54d3e..f8c1c9257e455 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/registration.php +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/registration.php @@ -1,6 +1,6 @@ reinitialize(); /** Apply method level fixtures if thy are available, apply class level fixtures otherwise */ $this->_applyFixtures($this->_getFixtures('method', $test) ?: $this->_getFixtures('class', $test)); } @@ -61,6 +62,9 @@ public function startTest(\PHPUnit_Framework_TestCase $test) public function endTest() { $this->_revertFixtures(); + /** @var $objectManager \Magento\TestFramework\ObjectManager */ + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $objectManager->get(\Magento\Eav\Model\Entity\AttributeCache::class)->clear(); } /** diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/OauthHelper.php b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/OauthHelper.php index 8db89d44152bd..081e4d4101ea3 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/OauthHelper.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/OauthHelper.php @@ -2,7 +2,7 @@ /** * Helper class for generating OAuth related credentials * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\TestFramework\Authentication; diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/CurlClient.php b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/CurlClient.php index a6c331e04ec9c..b9abedc421ff2 100644 --- a/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/CurlClient.php +++ b/dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/CurlClient.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/CartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/CartItemRepositoryTest.php index 054cda57fe899..1eba8c5e76773 100644 --- a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/CartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/CartItemRepositoryTest.php @@ -1,6 +1,6 @@ markTestSkipped('must be unskipped after fixing bug about wrong saving bundle option price'); $productSku = 'bundle-product'; $childSku = 'simple'; $optionIds = $this->getProductOptions(3); diff --git a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionRepositoryTest.php index 960163e31e4c7..8bf4089334d40 100644 --- a/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Bundle/Api/ProductOptionRepositoryTest.php @@ -1,7 +1,7 @@ markTestSkipped('Skipped, due to MAGETWO-46857'); $bundleProduct = $this->createFixedPriceBundleProduct(); $bundleProductOptions = $this->getBundleProductOptions($bundleProduct); - $existingSelectionId = $bundleProductOptions[0]['product_links'][0]['id']; - //Change the type of existing option $bundleProductOptions[0]['type'] = 'select'; - //unset product_links attribute - unset($bundleProductOptions[0]['product_links']); + $this->setBundleProductOptions($bundleProduct, $bundleProductOptions); $updatedProduct = $this->saveProduct($bundleProduct); @@ -162,7 +158,6 @@ public function testUpdateBundleModifyExistingOptionOnly() $this->assertEquals('select', $bundleOptions[0]['type']); $this->assertEquals('simple', $bundleOptions[0]['product_links'][0]['sku']); $this->assertEquals(1, $bundleOptions[0]['product_links'][0]['qty']); - $this->assertEquals($existingSelectionId, $bundleOptions[0]['product_links'][0]['id']); $this->assertEquals(20, $bundleOptions[0]['product_links'][0]['price']); $this->assertEquals(1, $bundleOptions[0]['product_links'][0]['price_type']); } diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetManagementTest.php index af56d58816ce9..008d963a9f3a6 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetManagementTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test get method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testGet() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/base-prices-information', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $response = $this->_webApiCall($serviceInfo, ['skus' => [self::SIMPLE_PRODUCT_SKU]]); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU); + + $this->assertNotEmpty($response); + $this->assertEquals($product->getPrice(), $response[0]['price']); + $this->assertEquals($product->getSku(), $response[0]['sku']); + } + + /** + * Test get method, called with not existing SKU. + */ + public function testGetWithInvalidSku() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/base-prices-information', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $expected = 'Requested product doesn\'t exist: %sku'; + + try { + $this->_webApiCall($serviceInfo, ['skus' => ['sku_of_not_exiting_product']]); + $this->fail("Expected throwing exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expected, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $error = $this->processRestExceptionResult($e); + $this->assertEquals($expected, $error['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + /** + * Test update method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testUpdate() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/base-prices', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Update', + ], + ]; + $newPrice = 9999; + $storeId = 0; + $response = $this->_webApiCall( + $serviceInfo, + [ + 'prices' => [ + [ + 'price' => $newPrice, + 'store_id' => $storeId, + 'sku' => self::SIMPLE_PRODUCT_SKU, + ] + ] + ] + ); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU); + + $this->assertEmpty($response); + $this->assertEquals($product->getPrice(), $newPrice); + } + + /** + * Test update method call with invalid parameters. + */ + public function testUpdateWithInvalidParameters() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/base-prices', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Update', + ], + ]; + $newPrice = -9999; + $storeId = 9999; + $response = $this->_webApiCall( + $serviceInfo, + [ + 'prices' => [ + [ + 'sku' => 'not_existing_sku', + 'price' => $newPrice, + 'store_id' => $storeId, + ] + ] + ] + ); + + $expectedResponse = [ + 0 => [ + 'message' => 'Invalid attribute %fieldName = %fieldValue.', + 'parameters' => [ + 'SKU', + 'not_existing_sku', + ] + ], + 1 => [ + 'message' => 'Invalid attribute %fieldName = %fieldValue.', + 'parameters' => [ + 'Price', + '-9999', + ] + ], + 2 => [ + 'message' => + 'Requested store is not found. Row ID: SKU = not_existing_sku, Store ID: 9999.', + 'parameters' => [ + 'not_existing_sku', + '9999' + ] + ] + ]; + + $this->assertEquals($expectedResponse, $response); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php index fd40f76aebf4e..e05965dfa66e9 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CartItemRepositoryTest.php @@ -1,6 +1,6 @@ checkIfTestable(); - $serviceInfo = [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH_SUFFIX @@ -71,8 +69,6 @@ public function saveDataProvider() */ public function testUpdateProduct($productLink, $productId, $productPosition = 0) { - $this->checkIfTestable(); - $serviceInfo = [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH_SUFFIX @@ -111,8 +107,6 @@ public function updateProductProvider() */ public function testDelete() { - $this->checkIfTestable(); - $serviceInfo = [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH_SUFFIX . '/' . $this->categoryId . @@ -153,20 +147,4 @@ private function isProductInCategory($categoryId, $productId, $productPosition) return false; } } - - /** - * MAGETWO-41737: Skip tests when the flag 'custom_categories_sort' is up - * @return void - */ - private function checkIfTestable() - { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - - /** @var \Magento\Framework\App\Config\ScopeConfigInterface $config */ - $config = $objectManager->get(\Magento\Framework\App\Config\ScopeConfigInterface::class); - - if ($config->getValue('catalog/custom_categories_sort') == 1) { - $this->markTestSkipped('Will be fixed after MAGETWO-41737'); - } - } } diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryListTest.php index 872ab5e6f7c19..272db13eaa273 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryListTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test get method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testGet() + { + $cost = 3057; + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $productRepository->save($productRepository->get(self::SIMPLE_PRODUCT_SKU)->setData('cost', $cost)); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/cost-information', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Delete', + ], + ]; + $response = $this->_webApiCall($serviceInfo, ['skus' => [self::SIMPLE_PRODUCT_SKU]]); + + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU); + + $this->assertNotEmpty($response); + $this->assertEquals($product->getCost(), $cost); + } + + /** + * Test get method, called with not existing SKUs. + */ + public function testGetWithInvalidSku() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/cost-information', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $expected = 'Requested products don\'t exist: %sku'; + + try { + $this->_webApiCall($serviceInfo, ['skus' => ['sku_of_not_exiting_product', 'invalid_sku']]); + $this->fail("Expected throwing exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expected, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $error = $this->processRestExceptionResult($e); + $this->assertEquals($expected, $error['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + /** + * Test update method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testUpdate() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/cost', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Update', + ], + ]; + $storeId = 0; + $newCost = 31337; + $response = $this->_webApiCall( + $serviceInfo, + [ + 'prices' => [ + [ + 'cost' => $newCost, + 'store_id' => $storeId, + 'sku' => self::SIMPLE_PRODUCT_SKU, + ] + ] + ] + ); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU); + $this->assertEmpty($response); + $this->assertEquals($product->getCost(), $newCost); + } + + /** + * Test update method call without SKU. + */ + public function testUpdateWithInvalidParameters() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/cost', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Update', + ], + ]; + $newCost = -9999; + $storeId = 9999; + $response = $this->_webApiCall( + $serviceInfo, + [ + 'prices' => [ + [ + 'sku' => 'not_existing_sku', + 'cost' => $newCost, + 'store_id' => $storeId + ] + ] + ] + ); + + $expectedResponse = [ + 0 => [ + 'message' => 'Invalid attribute %fieldName = %fieldValue.', + 'parameters' => [ + 'SKU', + 'not_existing_sku', + ] + ], + 1 => [ + 'message' => 'Invalid attribute Cost = -9999. Row ID: SKU = not_existing_sku, Store ID: 9999.', + 'parameters' => [ + '-9999', + 'not_existing_sku', + '9999' + ] + ], + 2 => [ + 'message' => 'Requested store is not found. Row ID: SKU = not_existing_sku, Store ID: 9999.', + 'parameters' => [ + 'not_existing_sku', + '9999' + ] + ] + ]; + + $this->assertEquals($expectedResponse, $response); + } + + /** + * Test delete method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testDelete() + { + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $productRepository->save($productRepository->get(self::SIMPLE_PRODUCT_SKU)->setData('cost', 777)); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/cost-delete', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Delete', + ], + ]; + $response = $this->_webApiCall($serviceInfo, ['skus' => [self::SIMPLE_PRODUCT_SKU]]); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU); + $this->assertTrue($response); + $this->assertNull($product->getCost()); + } + + /** + * Test delete method, called with not existing SKUs. + */ + public function testDeleteWithInvalidSku() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/cost-delete', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Delete', + ], + ]; + $expectedResponseMessage = 'Requested product doesn\'t exist: %sku'; + + try { + $this->_webApiCall($serviceInfo, ['skus' => ['sku_of_not_exiting_product']]); + $this->fail("Expected throwing exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expectedResponseMessage, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $error = $this->processRestExceptionResult($e); + $this->assertEquals($expectedResponseMessage, $error['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/OrderItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/OrderItemRepositoryTest.php index 1cc85d2175ef9..34d1322e4b00d 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/OrderItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/OrderItemRepositoryTest.php @@ -1,6 +1,6 @@ getTargetSimpleProduct(); $this->assertEquals('/m/a/magento_image.jpg', $targetProduct->getData('thumbnail')); - $this->assertNull($targetProduct->getData('image')); - $this->assertNull($targetProduct->getData('small_image')); + $this->assertEquals('no_selection', $targetProduct->getData('image')); + $this->assertEquals('no_selection', $targetProduct->getData('small_image')); $mediaGallery = $targetProduct->getData('media_gallery'); $this->assertCount(1, $mediaGallery['images']); $updatedImage = array_shift($mediaGallery['images']); diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php index cd8a43e5105ed..cb922dde8769c 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeOptionManagementInterfaceTest.php @@ -1,6 +1,6 @@ _markTestAsRestOnly('Fix inconsistencies in WSDL and Data interfaces'); $testAttributeCode = 'select_attribute'; @@ -67,18 +68,6 @@ public function testAdd() ], ]; - $optionData = [ - AttributeOptionInterface::LABEL => 'new color', - AttributeOptionInterface::SORT_ORDER => 100, - AttributeOptionInterface::IS_DEFAULT => true, - AttributeOptionInterface::STORE_LABELS => [ - [ - AttributeOptionLabelInterface::LABEL => 'DE label', - AttributeOptionLabelInterface::STORE_ID => 1, - ], - ], - ]; - $response = $this->_webApiCall( $serviceInfo, [ @@ -96,6 +85,37 @@ public function testAdd() ); } + /** + * @return array + */ + public function addDataProvider() + { + $optionPayload = [ + AttributeOptionInterface::LABEL => 'new color', + AttributeOptionInterface::SORT_ORDER => 100, + AttributeOptionInterface::IS_DEFAULT => true, + AttributeOptionInterface::STORE_LABELS => [ + [ + AttributeOptionLabelInterface::LABEL => 'DE label', + AttributeOptionLabelInterface::STORE_ID => 1, + ], + ], + ]; + + return [ + 'option_without_value_node' => [ + $optionPayload + ], + 'option_with_value_node_that_starts_with_text' => [ + array_merge($optionPayload, [AttributeOptionInterface::VALUE => 'some_text']) + ], + 'option_with_value_node_that_starts_with_a_number' => [ + array_merge($optionPayload, [AttributeOptionInterface::VALUE => '123_some_text']) + ], + + ]; + } + /** * @magentoApiDataFixture Magento/Catalog/Model/Product/Attribute/_files/select_attribute.php */ diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php index 0571aa9ddad03..572fc38a56b2a 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeRepositoryTest.php @@ -1,7 +1,7 @@ [ 'attribute_id' => $attribute['attribute_id'], 'attribute_code' => $attributeCode, + 'default_frontend_label' => 'default_label_new', 'frontend_labels' => [ - ['store_id' => 0, 'label' => 'front_lbl_new'], + ['store_id' => 1, 'label' => 'front_lbl_new'], ], "options" => [ //Update existing @@ -183,7 +184,7 @@ public function testUpdate() $this->assertEquals($attribute['attribute_id'], $result['attribute_id']); $this->assertEquals($attributeCode, $result['attribute_code']); - $this->assertEquals('front_lbl_new', $result['default_frontend_label']); + $this->assertEquals('default_label_new', $result['default_frontend_label']); //New option set as default $this->assertEquals($result['options'][3]['value'], $result['default_value']); $this->assertEquals("Default Blue Updated", $result['options'][1]['label']); diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeTypesListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeTypesListTest.php index 115c325284639..8adf477107f34 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeTypesListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeTypesListTest.php @@ -1,7 +1,7 @@ _markTestAsRestOnly(); $productSku = 'simple'; /** @var ProductRepository $productRepository */ $productRepository = $this->objectManager->create(ProductRepository::class); @@ -403,18 +404,9 @@ public function testUpdateNegative($optionData, $message) 'resourcePath' => '/V1/products/options/' . $optionId, 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT, ], - 'soap' => [ - 'service' => self::SERVICE_NAME, - 'serviceVersion' => 'V1', - 'operation' => self::SERVICE_NAME . 'Save', - ], ]; - if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { - $this->setExpectedException('SoapFault'); - } else { - $this->setExpectedException('Exception', $message, 400); - } + $this->setExpectedException('Exception', $message, 400); $this->_webApiCall($serviceInfo, ['option' => $optionData]); } diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionTypeListTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionTypeListTest.php index c4720c5de53ee..f0ef750ca9a01 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionTypeListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductCustomOptionTypeListTest.php @@ -1,7 +1,7 @@ get(\Magento\Framework\Registry::class); - $registry->unregister("isSecureArea"); - $registry->register("isSecureArea", true); - } - /** * Test removing association between product and website 1 * @magentoApiDataFixture Magento/Catalog/_files/product_with_two_websites.php @@ -169,9 +160,6 @@ public function testUpdateWithDeleteWebsites() $response[ProductInterface::EXTENSION_ATTRIBUTES_KEY]["website_ids"], $websitesData["website_ids"] ); - $this->deleteProduct($productBuilder[ProductInterface::SKU]); - $this->markAreaAsSecure(); - $website->delete(); } /** @@ -198,9 +186,6 @@ public function testDeleteAllWebsiteAssociations() $response[ProductInterface::EXTENSION_ATTRIBUTES_KEY]["website_ids"], $websitesData["website_ids"] ); - $this->deleteProduct($productBuilder[ProductInterface::SKU]); - $this->markAreaAsSecure(); - $website->delete(); } /** @@ -222,7 +207,7 @@ public function testCreateWithMultipleWebsites() $websitesData = [ 'website_ids' => [ 1, - $website->getId(), + (int) $website->getId(), ] ]; $productBuilder[ProductInterface::EXTENSION_ATTRIBUTES_KEY] = $websitesData; @@ -231,9 +216,6 @@ public function testCreateWithMultipleWebsites() $response[ProductInterface::EXTENSION_ATTRIBUTES_KEY]["website_ids"], $websitesData["website_ids"] ); - $this->deleteProduct($productBuilder[ProductInterface::SKU]); - $this->markAreaAsSecure(); - $website->delete(); } /** @@ -275,6 +257,35 @@ public function testCreateAllStoreCode($fixtureProduct) $this->deleteProduct($fixtureProduct[ProductInterface::SKU]); } + /** + * Test creating product with all store code on single store + * + * @param array $fixtureProduct + * @dataProvider productCreationProvider + */ + public function testCreateAllStoreCodeForSingleWebsite($fixtureProduct) + { + $response = $this->saveProduct($fixtureProduct, 'all'); + $this->assertArrayHasKey(ProductInterface::SKU, $response); + + /** @var \Magento\Store\Model\StoreManagerInterface $storeManager */ + $storeManager = \Magento\TestFramework\ObjectManager::getInstance()->get( + \Magento\Store\Model\StoreManagerInterface::class + ); + + foreach ($storeManager->getStores(true) as $store) { + $code = $store->getCode(); + if ($code === Store::ADMIN_CODE) { + continue; + } + $this->assertArrayHasKey( + ProductInterface::SKU, + $this->getProduct($fixtureProduct[ProductInterface::SKU], $code) + ); + } + $this->deleteProduct($fixtureProduct[ProductInterface::SKU]); + } + public function testCreateInvalidPriceFormat() { $this->_markTestAsRestOnly("In case of SOAP type casting is handled by PHP SoapServer, no need to test it"); @@ -684,6 +695,18 @@ public function testGetList() $this->assertNotNull($response['items'][0]['sku']); $this->assertEquals('simple', $response['items'][0]['sku']); + + $index = null; + foreach ($response['items'][0]['custom_attributes'] as $key => $customAttribute) { + if ($customAttribute['attribute_code'] == 'category_ids') { + $index = $key; + break; + } + } + $this->assertNotNull($index, 'Category information wasn\'t set'); + + $expectedResult = (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) ? ['string' => '2'] : ['2']; + $this->assertEquals($expectedResult, $response['items'][0]['custom_attributes'][$index]['value']); } /** diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiCurrencyTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiCurrencyTest.php new file mode 100644 index 0000000000000..a2616d956b61a --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiCurrencyTest.php @@ -0,0 +1,120 @@ +assignProductToWebsite($sku, $this->getWebsiteId('test')); + $product = $this->getProduct($sku); + $this->assertEquals(10, $product['price']); + + $product['price'] = 20; + $this->saveProduct($product, 'fixture_second_store'); + + $product = $this->getProduct($sku, 'fixture_third_store'); + $this->assertEquals(20, $product['price']); + } + + private function saveProduct($product, $storeCode = null) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $product['sku'], + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT + ], + 'soap' => [ + 'service' => self::PRODUCT_SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::PRODUCT_SERVICE_NAME . 'Save' + ] + ]; + + $requestData = ['product' => $product]; + return $this->_webApiCall($serviceInfo, $requestData, null, $storeCode); + } + + private function getProduct($sku, $storeCode = null) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::PRODUCTS_RESOURCE_PATH . '/' . $sku, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::PRODUCT_SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::PRODUCT_SERVICE_NAME . 'get' + ] + ]; + + $requestData = ['sku' => $sku]; + return $this->_webApiCall($serviceInfo, $requestData, null, $storeCode); + } + + private function getWebsiteId($websiteCode) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::WEBSITES_RESOURCE_PATH, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::WEBSITES_SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::WEBSITES_SERVICE_NAME . 'GetList' + ] + ]; + + $response = $this->_webApiCall($serviceInfo); + $websiteId = null; + foreach ($response as $website) { + if ($website['code'] == $websiteCode) { + $websiteId = $website['id']; + } + } + $this->assertNotNull($websiteId); + return $websiteId; + } + + private function assignProductToWebsite($sku, $websiteId) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $sku . '/websites', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::WEBSITE_LINK_SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::WEBSITE_LINK_SERVICE_NAME . 'save' + ] + ]; + + $requestData = [ + "productWebsiteLink" => [ + "websiteId" => $websiteId, + "sku" => $sku + ] + ]; + $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiStoreTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiStoreTest.php index fab38602f6049..bcc3eeccae1f1 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiStoreTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiStoreTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test get method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testGet() + { + $specialPrice = 3057; + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU, true); + $product->setData('special_price', $specialPrice); + $productRepository->save($product); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/special-price-information', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $response = $this->_webApiCall($serviceInfo, ['skus' => [self::SIMPLE_PRODUCT_SKU]]); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU); + $this->assertNotEmpty($response); + $this->assertEquals($product->getSpecialPrice(), $response[0]['price']); + } + + /** + * Test get method, called with not existing SKUs. + */ + public function testGetWithInvalidSku() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/special-price-information', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $expected = 'Requested products don\'t exist: %sku'; + try { + $this->_webApiCall($serviceInfo, ['skus' => ['sku_of_not_exiting_product', 'invalid_sku_1']]); + $this->fail("Expected throwing exception"); + } catch (\SoapFault $e) { + $this->assertContains( + $expected, + $e->getMessage(), + "SoapFault does not contain expected message." + ); + } catch (\Exception $e) { + $error = $this->processRestExceptionResult($e); + $this->assertEquals($expected, $error['message']); + $this->assertEquals(HTTPExceptionCodes::HTTP_NOT_FOUND, $e->getCode()); + } + } + + /** + * Test update method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php + */ + public function testUpdate() + { + $sku = 'virtual-product'; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/special-price', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Update', + ], + ]; + $storeId = 0; + $newPrice = 31337; + $response = $this->_webApiCall( + $serviceInfo, + [ + 'prices' => [ + [ + 'price' => $newPrice, + 'store_id' => $storeId, + 'sku' => $sku, + 'price_from' => '2037-01-19 03:14:07', + 'price_to' => '2038-01-19 03:14:07', + ] + ] + ] + ); + $this->assertEmpty($response); + } + + /** + * Test delete method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testDelete() + { + $specialPrice = 3057; + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $fromDate = '1970-01-01 00:00:01'; + $toDate = '2038-01-19 03:14:07'; + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU, true); + $product->setData('special_price', $specialPrice) + ->setData('special_from_date', $fromDate) + ->setData('special_to_date', $toDate); + $productRepository->save($product); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/special-price-delete', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Delete', + ], + ]; + $response = $this->_webApiCall( + $serviceInfo, + [ + 'prices' => [ + [ + 'price' => $specialPrice, + 'store_id' => 0, + 'sku' => self::SIMPLE_PRODUCT_SKU, + 'price_from' => $fromDate, + 'price_to' => $toDate, + ] + ] + ] + ); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get(self::SIMPLE_PRODUCT_SKU, false, null, true); + $this->assertEmpty($response); + $this->assertNull($product->getSpecialPrice()); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/TierPriceStorageTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/TierPriceStorageTest.php new file mode 100644 index 0000000000000..bf9d65af13e50 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/TierPriceStorageTest.php @@ -0,0 +1,270 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * Test get method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testGet() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/tier-prices-information', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + $response = $this->_webApiCall($serviceInfo, ['skus' => [self::SIMPLE_PRODUCT_SKU]]); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $tierPrices = $productRepository->get(self::SIMPLE_PRODUCT_SKU)->getTierPrices(); + $this->assertNotEmpty($response); + $this->assertEquals(count($response), count($tierPrices)); + + foreach ($response as $item) { + $this->assertTrue($this->isPriceCorrect($item, $tierPrices)); + } + } + + /** + * Test update method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testUpdate() + { + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $prices = $productRepository->get(self::SIMPLE_PRODUCT_SKU)->getTierPrices(); + $tierPrice = array_shift($prices); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/tier-prices', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Update', + ], + ]; + $newPrice = [ + 'price' => 40, + 'price_type' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT, + 'website_id' => 0, + 'sku' => self::SIMPLE_PRODUCT_SKU, + 'customer_group' => 'ALL GROUPS', + 'quantity' => 7778 + ]; + $updatedPrice = [ + 'price' => 778, + 'price_type' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_FIXED, + 'website_id' => 0, + 'sku' => self::SIMPLE_PRODUCT_SKU, + 'customer_group' => 'not logged in', + 'quantity' => $tierPrice->getQty() + ]; + $response = $this->_webApiCall($serviceInfo, ['prices' => [$updatedPrice, $newPrice]]); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $tierPrices = $productRepository->get(self::SIMPLE_PRODUCT_SKU)->getTierPrices(); + $this->assertEmpty($response); + $this->assertTrue($this->isPriceCorrect($newPrice, $tierPrices)); + $this->assertTrue($this->isPriceCorrect($updatedPrice, $tierPrices)); + } + + /** + * Call update method with specifying new website value for tier price with all websites value. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testUpdateWebsiteForAllWebsites() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/tier-prices', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Update', + ], + ]; + $invalidPrice = [ + 'price' => 40, + 'price_type' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_FIXED, + 'website_id' => 2, + 'sku' => self::SIMPLE_PRODUCT_SKU, + 'customer_group' => 'not logged in', + 'quantity' => 3 + ]; + $response = $this->_webApiCall($serviceInfo, ['prices' => [$invalidPrice]]); + $this->assertNotEmpty($response); + $this->assertEquals('Invalid attribute %fieldName = %fieldValue.', $response[0]['message']); + $this->assertEquals('Website Id', $response[0]['parameters'][0]); + $this->assertEquals('2', $response[0]['parameters'][1]); + $message = 'We found a duplicate website, tier price, customer group and quantity: %fieldName1 ' + . '= %fieldValue1, %fieldName2 = %fieldValue2, %fieldName3 = %fieldValue3.'; + $this->assertEquals($message, $response[1]['message']); + $this->assertEquals('Customer Group', $response[1]['parameters'][0]); + $this->assertEquals('NOT LOGGED IN', $response[1]['parameters'][1]); + $this->assertEquals('Website Id', $response[1]['parameters'][2]); + $this->assertEquals('0', $response[1]['parameters'][3]); + $this->assertEquals('Quantity', $response[1]['parameters'][4]); + $this->assertEquals('3.0000', $response[1]['parameters'][5]); + } + + /** + * Test replace method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testReplace() + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/tier-prices', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Replace', + ], + ]; + $newPrices = [ + [ + 'price' => 50, + 'price_type' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT, + 'website_id' => 0, + 'sku' => self::SIMPLE_PRODUCT_SKU, + 'customer_group' => 'general', + 'quantity' => 7778 + ], + [ + 'price' => 70, + 'price_type' => \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_FIXED, + 'website_id' => 0, + 'sku' => self::SIMPLE_PRODUCT_SKU, + 'customer_group' => 'not logged in', + 'quantity' => 33 + ] + ]; + $response = $this->_webApiCall($serviceInfo, ['prices' => $newPrices]); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $tierPrices = $productRepository->get(self::SIMPLE_PRODUCT_SKU)->getTierPrices(); + $this->assertEmpty($response); + $this->assertEquals(count($newPrices), count($tierPrices)); + } + + /** + * Test delete method. + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testDelete() + { + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $tierPrices = $productRepository->get(self::SIMPLE_PRODUCT_SKU)->getTierPrices(); + $pricesToStore = array_pop($tierPrices); + $pricesToDelete = []; + foreach ($tierPrices as $tierPrice) { + $tierPriceValue = $tierPrice->getExtensionAttributes()->getPercentageValue() + ?: $tierPrice->getValue(); + $priceType = $tierPrice->getExtensionAttributes()->getPercentageValue() + ? \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT + : \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_FIXED; + $customerGroup = $tierPrice->getCustomerGroupId() == \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID + ? 'NOT LOGGED IN' + : 'ALL GROUPS'; + $pricesToDelete[] = [ + 'price' => $tierPriceValue, + 'price_type' => $priceType, + 'website_id' => 0, + 'customer_group' => $customerGroup, + 'sku' => self::SIMPLE_PRODUCT_SKU, + 'quantity' => $tierPrice->getQty() + + ]; + } + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/tier-prices-delete', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Delete', + ], + ]; + $response = $this->_webApiCall($serviceInfo, ['prices' => $pricesToDelete]); + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $tierPrices = $productRepository->get(self::SIMPLE_PRODUCT_SKU)->getTierPrices(); + $tierPrice = $tierPrices[0]; + $this->assertEmpty($response); + $this->assertEquals(1, count($tierPrices)); + $this->assertEquals($pricesToStore, $tierPrice); + } + + /** + * Check prise exists and is correct. + * + * @param array $price + * @param array $tierPrices + * @return bool + */ + private function isPriceCorrect(array $price, array $tierPrices) + { + $isCorrect = false; + + foreach ($tierPrices as $tierPrice) { + $priceIsCorrect = $price['price_type'] === \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT + ? (float)$tierPrice->getExtensionAttributes()->getPercentageValue() === (float)$price['price'] + : (float)$tierPrice->getValue() === (float)$price['price']; + if ( + $priceIsCorrect + && (int)$tierPrice->getQty() === (int)$price['quantity'] + && $tierPrice->getExtensionAttributes()->getWebsiteId() == $price['website_id'] + ) { + $isCorrect = true; + break; + } + } + + return $isCorrect; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php index bdc0bf12e49fd..9488a3e376143 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/_files/product_options.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->attributeRepository = $this->objectManager->get(\Magento\Eav\Model\AttributeRepository::class); + } + /** * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php */ @@ -40,14 +61,76 @@ public function testGetChildren() } /** - * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_simple_77.php * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_simple_77.php * @magentoApiDataFixture Magento/ConfigurableProduct/_files/delete_association.php */ public function testAddChild() { $productSku = 'configurable'; $childSku = 'simple_77'; + $res = $this->addChild($productSku, $childSku); + $this->assertTrue($res); + } + + /** + * Test the full flow of creating a configurable product and adding a child via REST + * + * @magentoApiDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php + */ + public function testAddChildFullRestCreation() + { + $productSku = 'configurable-product-sku'; + $childSku = 'simple-product-sku'; + + $this->createConfigurableProduct($productSku); + $attribute = $this->attributeRepository->get('catalog_product', 'test_configurable'); + $attributeValue = $attribute->getOptions()[1]->getValue(); + $this->addOptionToConfigurableProduct($productSku, $attribute->getAttributeId(), $attributeValue); + $this->createSimpleProduct($childSku, $attributeValue); + $res = $this->addChild($productSku, $childSku); + $this->assertTrue($res); + + // confirm that the simple product was added + $children = $this->getChildren($productSku); + $added = false; + foreach ($children as $child) { + if ($child['sku'] == $childSku) { + $added = true; + break; + } + } + $this->assertTrue($added); + + // clean up products + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $productSku, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE + ], + 'soap' => [ + 'service' => 'catalogProductRepositoryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogProductRepositoryV1DeleteById', + ], + ]; + $this->_webApiCall($serviceInfo, ['sku' => $productSku]); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products/' . $childSku, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE + ], + 'soap' => [ + 'service' => 'catalogProductRepositoryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogProductRepositoryV1DeleteById', + ], + ]; + $this->_webApiCall($serviceInfo, ['sku' => $childSku]); + } + + private function addChild($productSku, $childSku) + { $serviceInfo = [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH . '/' . $productSku . '/child', @@ -59,8 +142,90 @@ public function testAddChild() 'operation' => self::SERVICE_NAME . 'AddChild' ] ]; - $res = $this->_webApiCall($serviceInfo, ['sku' => $productSku, 'childSku' => $childSku]); - $this->assertTrue($res); + return $this->_webApiCall($serviceInfo, ['sku' => $productSku, 'childSku' => $childSku]); + } + + protected function createConfigurableProduct($productSku) + { + $requestData = [ + 'product' => [ + 'sku' => $productSku, + 'name' => 'configurable-product-' . $productSku, + 'type_id' => 'configurable', + 'price' => 50, + 'attribute_set_id' => 4 + ] + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST + ], + 'soap' => [ + 'service' => 'catalogProductRepositoryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogProductRepositoryV1Save', + ], + ]; + return $this->_webApiCall($serviceInfo, $requestData); + } + + protected function addOptionToConfigurableProduct($productSku, $attributeId, $attributeValue) + { + $requestData = [ + 'sku' => $productSku, + 'option' => [ + 'attribute_id' => $attributeId, + 'label' => 'test_configurable', + 'position' => 0, + 'is_use_default' => true, + 'values' => [ + ['value_index' => $attributeValue], + ] + ] + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/configurable-products/'. $productSku .'/options', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'configurableProductOptionRepositoryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'configurableProductOptionRepositoryV1Save', + ], + ]; + return $this->_webApiCall($serviceInfo, $requestData); + } + + protected function createSimpleProduct($sku, $attributeValue) + { + $requestData = [ + 'product' => [ + 'sku' => $sku, + 'name' => 'simple-product-' . $sku, + 'type_id' => 'simple', + 'attribute_set_id' => 4, + 'price' => 3.62, + 'status' => 1, + 'visibility' => 4, + 'custom_attributes' => [ + ['attribute_code' => 'test_configurable', 'value' => $attributeValue], + ] + ] + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/products', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => 'catalogProductRepositoryV1', + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => 'catalogProductRepositoryV1Save', + ], + ]; + return $this->_webApiCall($serviceInfo, $requestData); } /** @@ -93,7 +258,7 @@ protected function removeChild($productSku, $childSku) /** * @param string $productSku - * @return string + * @return string[] */ protected function getChildren($productSku) { diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php index 46b949ea47245..28824f812c4e4 100644 --- a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php @@ -1,7 +1,7 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $appConfig = $this->objectManager->get(Config::class); + $appConfig->clean(); } public function tearDown() diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php index feb1d10634cde..ad782a7aedf53 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php @@ -1,6 +1,6 @@ objectManager->create(\Magento\Quote\Model\Quote::class); @@ -125,8 +126,9 @@ public function testSetAddress() 'fax' => '44332255', ]; $requestData = [ - "cartId" => $cartId, + 'cartId' => $cartId, 'address' => $addressData, + 'useForShipping' => $useForShipping ]; $addressId = $this->_webApiCall($serviceInfo, $requestData); @@ -149,5 +151,27 @@ public function testSetAddress() foreach ($addressData as $key => $value) { $this->assertEquals($value, $savedData[$key]); } + $address = $quote->getShippingAddress(); + $address->getRegionCode(); + $savedData = $address->getData(); + if ($useForShipping) { + //check that shipping address set + $this->assertEquals('shipping', $savedData['address_type']); + $this->assertEquals(1, $savedData['same_as_billing']); + //check the rest of fields + foreach ($addressData as $key => $value) { + $this->assertEquals($value, $savedData[$key]); + } + } else { + $this->assertEquals(0, $savedData['same_as_billing']); + } + } + + public function setAddressDataProvider() + { + return [ + [true], + [false] + ]; } } diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php index e04b3a1e5d2ab..aed14154a4426 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php @@ -1,7 +1,7 @@ markTestSkipped('Will be fixed after MAGETWO-35573'); /** @var \Magento\Quote\Model\Quote $quote */ $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); $quote->load('test_order_1', 'reserved_order_id'); @@ -86,6 +85,7 @@ public function testGetTotals() Totals::KEY_BASE_SHIPPING_INCL_TAX => $shippingAddress->getBaseShippingInclTax(), Totals::KEY_BASE_CURRENCY_CODE => $quote->getBaseCurrencyCode(), Totals::KEY_QUOTE_CURRENCY_CODE => $quote->getQuoteCurrencyCode(), + Totals::KEY_ITEMS_QTY => $quote->getItemsQty(), Totals::KEY_ITEMS => [$this->getQuoteItemTotalsData($quote)], ]; @@ -93,7 +93,17 @@ public function testGetTotals() $data = $this->formatTotalsData($data); - $this->assertEquals($data, $this->_webApiCall($this->getServiceInfoForTotalsService($cartId), $requestData)); + $actual = $this->_webApiCall($this->getServiceInfoForTotalsService($cartId), $requestData); + + unset($actual['items'][0]['options']); + unset($actual['weee_tax_applied_amount']); + + unset($actual['total_segments']); + if (array_key_exists('extension_attributes', $actual)) { + unset($actual['extension_attributes']); + } + + $this->assertEquals($data, $actual); } /** @@ -162,6 +172,7 @@ protected function getQuoteItemTotalsData(\Magento\Quote\Model\Quote $quote) $item = array_shift($items); return [ + ItemTotals::KEY_ITEM_ID => $item->getItemId(), ItemTotals::KEY_PRICE => $item->getPrice(), ItemTotals::KEY_BASE_PRICE => $item->getBasePrice(), ItemTotals::KEY_QTY => $item->getQty(), @@ -178,6 +189,9 @@ protected function getQuoteItemTotalsData(\Magento\Quote\Model\Quote $quote) ItemTotals::KEY_BASE_PRICE_INCL_TAX => $item->getBasePriceInclTax(), ItemTotals::KEY_ROW_TOTAL_INCL_TAX => $item->getRowTotalInclTax(), ItemTotals::KEY_BASE_ROW_TOTAL_INCL_TAX => $item->getBaseRowTotalInclTax(), + ItemTotals::KEY_WEEE_TAX_APPLIED_AMOUNT => $item->getWeeeTaxAppliedAmount(), + ItemTotals::KEY_WEEE_TAX_APPLIED => $item->getWeeeTaxApplied(), + ItemTotals::KEY_NAME => $item->getName(), ]; } } diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCouponManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCouponManagementTest.php index 5427ac6542df9..532a07648cb1d 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCouponManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCouponManagementTest.php @@ -1,7 +1,7 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/SalesRule/_files/cart_rule_free_shipping.php + * @magentoApiDataFixture Magento/Sales/_files/quote.php + */ + public function testEstimateByExtendedAddress() + { + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); + $quote->load('test01', 'reserved_order_id'); + $cartId = $quote->getId(); + if (!$cartId) { + $this->fail('quote fixture failed'); + } + + /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ + $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + ->create(); + $quoteIdMask->load($cartId, 'quote_id'); + //Use masked cart Id + $cartId = $quoteIdMask->getMaskedId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/guest-carts/' . $cartId . '/estimate-shipping-methods', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_NAME . 'EstimateByExtendedAddress', + ], + ]; + if (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) { + /** @var \Magento\Quote\Model\Quote\Address $address */ + $address = $quote->getBillingAddress(); + + $data = [ + AddressInterface::KEY_ID => (int)$address->getId(), + AddressInterface::KEY_REGION => $address->getRegion(), + AddressInterface::KEY_REGION_ID => $address->getRegionId(), + AddressInterface::KEY_REGION_CODE => $address->getRegionCode(), + AddressInterface::KEY_COUNTRY_ID => $address->getCountryId(), + AddressInterface::KEY_STREET => $address->getStreet(), + AddressInterface::KEY_COMPANY => $address->getCompany(), + AddressInterface::KEY_TELEPHONE => $address->getTelephone(), + AddressInterface::KEY_POSTCODE => $address->getPostcode(), + AddressInterface::KEY_CITY => $address->getCity(), + AddressInterface::KEY_FIRSTNAME => $address->getFirstname(), + AddressInterface::KEY_LASTNAME => $address->getLastname(), + AddressInterface::KEY_CUSTOMER_ID => $address->getCustomerId(), + AddressInterface::KEY_EMAIL => $address->getEmail(), + AddressInterface::SAME_AS_BILLING => $address->getSameAsBilling(), + AddressInterface::CUSTOMER_ADDRESS_ID => $address->getCustomerAddressId(), + AddressInterface::SAVE_IN_ADDRESS_BOOK => $address->getSaveInAddressBook(), + ]; + + $requestData = [ + 'cartId' => $cartId, + 'address' => $data + ]; + } else { + $requestData = [ + 'address' => [ + 'country_id' => "US", + 'postcode' => null, + 'region' => null, + 'region_id' => null + ], + ]; + } + // Cart must be anonymous (see fixture) + $this->assertEmpty($quote->getCustomerId()); + + $result = $this->_webApiCall($serviceInfo, $requestData); + $this->assertNotEmpty($result); + $this->assertEquals(1, count($result)); + foreach ($result as $rate) { + $this->assertEquals("flatrate", $rate['carrier_code']); + $this->assertEquals(0, $rate['amount']); + } + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestShippingMethodManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestShippingMethodManagementTest.php index 9a1673f82f738..ef85f3b9b835a 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestShippingMethodManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestShippingMethodManagementTest.php @@ -1,6 +1,6 @@ markTestSkipped('Will be fixed after MAGETWO-35573'); $this->_markTestAsRestOnly(); $this->quote->load('test_order_1', 'reserved_order_id'); @@ -89,9 +88,9 @@ public function testGetListForMyCart() ); $token = $customerTokenService->createCustomerAccessToken('customer@example.com', 'password'); - /** @var \Magento\Quote\Api\ShippingMethodManagementInterface $shippingMethodManagementService */ + /** @var \Magento\Quote\Model\ShippingMethodManagementInterface $shippingMethodManagementService */ $shippingMethodManagementService = $this->objectManager->create( - \Magento\Quote\Api\ShippingMethodManagementInterface::class + \Magento\Quote\Model\ShippingMethodManagementInterface::class ); $shippingMethodManagementService->set($this->quote->getId(), 'flatrate', 'flatrate'); diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php index 39c8a7bf8fe91..62e314792da89 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php @@ -1,6 +1,6 @@ markTestSkipped('You can not cancel Credit Memo'); $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); /** @var \Magento\Sales\Model\ResourceModel\Order\Creditmemo\Collection $creditmemoCollection */ @@ -44,7 +45,6 @@ public function testCreditmemoCancel() ], ]; $requestData = ['id' => $creditmemo->getId()]; - $result = $this->_webApiCall($serviceInfo, $requestData); - $this->assertTrue($result); + $this->_webApiCall($serviceInfo, $requestData); } } diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCommentsListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCommentsListTest.php index 83e3e81316ad4..6ec063dacdc42 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCommentsListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoCommentsListTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ protected function prepareOrder() { /** @var \Magento\Sales\Model\Order $orderBuilder */ @@ -41,6 +44,8 @@ protected function prepareOrder() $orderPaymentFactory = $this->objectManager->get(\Magento\Sales\Model\Order\PaymentFactory::class); /** @var \Magento\Sales\Model\Order\AddressRepository $orderAddressRepository */ $orderAddressRepository = $this->objectManager->get(\Magento\Sales\Model\Order\AddressRepository::class); + /** @var \Magento\Store\Model\StoreManagerInterface $storeManager */ + $storeManager = $this->objectManager->get(\Magento\Store\Model\StoreManagerInterface::class); $order = $orderFactory->create( ['data' => $this->getDataStructure(\Magento\Sales\Api\Data\OrderInterface::class)] @@ -68,6 +73,32 @@ protected function prepareOrder() $order->setCustomerEmail($email); $order->setBaseGrandTotal(100); $order->setGrandTotal(100); + $order->setShippingDescription('Flat Rate - Fixed'); + $order->setIsVirtual(0); + $order->setStoreId($storeManager->getDefaultStoreView()->getId()); + $order->setBaseDiscountAmount(0); + $order->setBaseShippingAmount(5); + $order->setBaseShippingTaxAmount(0); + $order->setBaseSubtotal(100); + $order->setBaseTaxAmount(0); + $order->setBaseToGlobalRate(1); + $order->setBaseToOrderRate(1); + $order->setDiscountAmount(0); + $order->setShippingAmount(0); + $order->setShippingTaxAmount(0); + $order->setStoreToOrderRate(0); + $order->setBaseToOrderRate(0); + $order->setSubtotal(100); + $order->setTaxAmount(0); + $order->setTotalQtyOrdered(1); + $order->setCustomerIsGuest(1); + $order->setCustomerNoteNotify(0); + $order->setCustomerGroupId(0); + $order->setBaseSubtotalInclTax(100); + $order->setWeight(1); + $order->setBaseCurrencyCode('USD'); + $order->setShippingInclTax(5); + $order->setBaseShippingInclTax(5); $this->addProductOption($orderItem); @@ -82,12 +113,39 @@ protected function prepareOrder() $orderAddressBilling->setFirstname('First Name'); $orderAddressBilling->setTelephone('+00(000)-123-45-57'); $orderAddressBilling->setStreet(['Street']); - $orderAddressBilling->setCountryId(1); + $orderAddressBilling->setCountryId('US'); + $orderAddressBilling->setRegion('California'); $orderAddressBilling->setAddressType('billing'); + $orderAddressBilling->setRegionId(12); + + $orderAddressShipping = $orderAddressRepository->create(); + $orderAddressShipping->setCity('City2'); + $orderAddressShipping->setPostcode('12345'); + $orderAddressShipping->setLastname('Last Name2'); + $orderAddressShipping->setFirstname('First Name2'); + $orderAddressShipping->setTelephone('+00(000)-123-45-57'); + $orderAddressShipping->setStreet(['Street']); + $orderAddressShipping->setCountryId('US'); + $orderAddressShipping->setRegion('California'); + $orderAddressShipping->setAddressType('shipping'); + $orderAddressShipping->setRegionId(12); $orderData = $order->getData(); $orderData['billing_address'] = $orderAddressBilling->getData(); $orderData['billing_address']['street'] = ['Street']; + $address = $orderAddressShipping->getData(); + $address['street'] = ['Street']; + $orderData['extension_attributes']['shipping_assignments'] = + [ + [ + 'shipping' => [ + 'address' => $address, + 'method' => 'Flat Rate - Fixed' + ], + 'items' => [$orderItem->getData()], + 'stock_id' => null, + ] + ]; return $orderData; } @@ -172,5 +230,8 @@ public function testOrderCreate() $this->assertTrue((bool)$model->getId()); $this->assertEquals($order['base_grand_total'], $model->getBaseGrandTotal()); $this->assertEquals($order['grand_total'], $model->getGrandTotal()); + $this->assertNotNull($model->getShippingAddress()); + $this->assertTrue((bool)$model->getShippingAddress()->getId()); + $this->assertEquals('Flat Rate - Fixed', $model->getShippingMethod()); } } diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderEmailTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderEmailTest.php index 689acb4c44891..b2b34cfd79e29 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderEmailTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderEmailTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->creditmemoRepository = $this->objectManager->get( + \Magento\Sales\Api\CreditmemoRepositoryInterface::class + ); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order_with_shipping_and_invoice.php + */ + public function testShortRequest() + { + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + + $result = $this->_webApiCall( + $this->getServiceData($existingOrder), + ['orderId' => $existingOrder->getEntityId()] + ); + + $this->assertNotEmpty( + $result, + 'Failed asserting that the received response is correct' + ); + + /** @var \Magento\Sales\Model\Order $updatedOrder */ + $updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId($existingOrder->getIncrementId()); + + try { + $creditmemo = $this->creditmemoRepository->get($result); + + $expectedItems = $this->getOrderItems($existingOrder); + $actualCreditmemoItems = $this->getCreditmemoItems($creditmemo); + $actualRefundedOrderItems = $this->getRefundedOrderItems($updatedOrder); + + $this->assertEquals( + $expectedItems, + $actualCreditmemoItems, + 'Failed asserting that the Creditmemo contains all requested items' + ); + + $this->assertEquals( + $expectedItems, + $actualRefundedOrderItems, + 'Failed asserting that all requested order items were refunded' + ); + + $this->assertEquals( + $creditmemo->getShippingAmount(), + $existingOrder->getShippingAmount(), + 'Failed asserting that the Creditmemo contains correct shipping amount' + ); + + $this->assertEquals( + $creditmemo->getShippingAmount(), + $updatedOrder->getShippingRefunded(), + 'Failed asserting that proper shipping amount of the Order was refunded' + ); + + $this->assertNotEquals( + $existingOrder->getStatus(), + $updatedOrder->getStatus(), + 'Failed asserting that order status was changed' + ); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->fail('Failed asserting that Creditmemo was created'); + } + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order_with_shipping_and_invoice.php + */ + public function testFullRequest() + { + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + + $expectedItems = $this->getOrderItems($existingOrder); + $expectedItems[0]['qty'] = $expectedItems[0]['qty'] - 1; + + $expectedComment = [ + 'comment' => 'Test Comment', + 'is_visible_on_front' => 1 + ]; + + $expectedShippingAmount = 15; + $expectedAdjustmentPositive = 5.53; + $expectedAdjustmentNegative = 5.53; + + $result = $this->_webApiCall( + $this->getServiceData($existingOrder), + [ + 'orderId' => $existingOrder->getEntityId(), + 'items' => $expectedItems, + 'comment' => $expectedComment, + 'arguments' => [ + 'shipping_amount' => $expectedShippingAmount, + 'adjustment_positive' => $expectedAdjustmentPositive, + 'adjustment_negative' => $expectedAdjustmentNegative + ] + ] + ); + + $this->assertNotEmpty( + $result, + 'Failed asserting that the received response is correct' + ); + + /** @var \Magento\Sales\Model\Order $updatedOrder */ + $updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId($existingOrder->getIncrementId()); + + try { + $creditmemo = $this->creditmemoRepository->get($result); + + $actualCreditmemoItems = $this->getCreditmemoItems($creditmemo); + $actualCreditmemoComment = $this->getRecentComment($creditmemo); + $actualRefundedOrderItems = $this->getRefundedOrderItems($updatedOrder); + + $this->assertEquals( + $expectedItems, + $actualCreditmemoItems, + 'Failed asserting that the Creditmemo contains all requested items' + ); + + $this->assertEquals( + $expectedItems, + $actualRefundedOrderItems, + 'Failed asserting that all requested order items were refunded' + ); + + $this->assertEquals( + $expectedComment, + $actualCreditmemoComment, + 'Failed asserting that the Creditmemo contains correct comment' + ); + + $this->assertEquals( + $expectedShippingAmount, + $creditmemo->getShippingAmount(), + 'Failed asserting that the Creditmemo contains correct shipping amount' + ); + + $this->assertEquals( + $expectedShippingAmount, + $updatedOrder->getShippingRefunded(), + 'Failed asserting that proper shipping amount of the Order was refunded' + ); + + $this->assertEquals( + $expectedAdjustmentPositive, + $creditmemo->getAdjustmentPositive(), + 'Failed asserting that the Creditmemo contains correct positive adjustment' + ); + + $this->assertEquals( + $expectedAdjustmentNegative, + $creditmemo->getAdjustmentNegative(), + 'Failed asserting that the Creditmemo contains correct negative adjustment' + ); + + $this->assertEquals( + $existingOrder->getStatus(), + $updatedOrder->getStatus(), + 'Failed asserting that order status was NOT changed' + ); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->fail('Failed asserting that Creditmemo was created'); + } + } + + /** + * Prepares and returns info for API service. + * + * @param \Magento\Sales\Api\Data\OrderInterface $order + * + * @return array + */ + private function getServiceData(\Magento\Sales\Api\Data\OrderInterface $order) + { + return [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getEntityId() . '/refund', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'execute', + ] + ]; + } + + /** + * Gets all items of given Order in proper format. + * + * @param \Magento\Sales\Model\Order $order + * + * @return array + */ + private function getOrderItems(\Magento\Sales\Model\Order $order) + { + $items = []; + + /** @var \Magento\Sales\Api\Data\OrderItemInterface $item */ + foreach ($order->getAllItems() as $item) { + $items[] = [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ]; + } + + return $items; + } + + /** + * Gets refunded items of given Order in proper format. + * + * @param \Magento\Sales\Model\Order $order + * + * @return array + */ + private function getRefundedOrderItems(\Magento\Sales\Model\Order $order) + { + $items = []; + + /** @var \Magento\Sales\Api\Data\OrderItemInterface $item */ + foreach ($order->getAllItems() as $item) { + if ($item->getQtyRefunded() > 0) { + $items[] = [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyRefunded(), + ]; + } + } + + return $items; + } + + /** + * Gets all items of given Creditmemo in proper format. + * + * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo + * + * @return array + */ + private function getCreditmemoItems(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo) + { + $items = []; + + /** @var \Magento\Sales\Api\Data\CreditmemoItemInterface $item */ + foreach ($creditmemo->getItems() as $item) { + $items[] = [ + 'order_item_id' => $item->getOrderItemId(), + 'qty' => $item->getQty(), + ]; + } + + return $items; + } + + /** + * Gets the most recent comment of given Creditmemo in proper format. + * + * @param \Magento\Sales\Api\Data\CreditmemoInterface $creditmemo + * + * @return array|null + */ + private function getRecentComment(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo) + { + $comments = $creditmemo->getComments(); + + if ($comments) { + $comment = reset($comments); + + return [ + 'comment' => $comment->getComment(), + 'is_visible_on_front' => $comment->getIsVisibleOnFront(), + ]; + } + + return null; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php index 8de7c4dc7f65b..ef7c8ee348d10 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @dataProvider dataProvider + * @magentoApiDataFixture Magento/Sales/_files/order_with_shipping_and_invoice.php + */ + public function testRefundWithReturnItemsToStock($qtyRefund) + { + $productSku = 'simple'; + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + $orderItems = $existingOrder->getItems(); + $orderItem = array_shift($orderItems); + $expectedItems = [['order_item_id' => $orderItem->getItemId(), 'qty' => $qtyRefund]]; + $qtyBeforeRefund = $this->getQtyInStockBySku($productSku); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $existingOrder->getEntityId() . '/refund', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_REFUND_ORDER_NAME, + 'serviceVersion' => 'V1', + 'operation' => self::SERVICE_REFUND_ORDER_NAME . 'execute', + ] + ]; + + $this->_webApiCall( + $serviceInfo, + [ + 'orderId' => $existingOrder->getEntityId(), + 'items' => $expectedItems, + 'arguments' => [ + 'extension_attributes' => [ + 'return_to_stock_items' => [ + (int)$orderItem->getItemId() + ], + ], + ], + ] + ); + + $qtyAfterRefund = $this->getQtyInStockBySku($productSku); + + try { + $this->assertEquals( + $qtyBeforeRefund + $expectedItems[0]['qty'], + $qtyAfterRefund, + 'Failed asserting qty of returned items incorrect.' + ); + + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->fail('Failed asserting that Creditmemo was created'); + } + } + + /** + * @return array + */ + public function dataProvider() + { + return [ + 'refundAllOrderItems' => [2], + 'refundPartition' => [1], + ]; + } + + /** + * @param string $sku + * @return int + */ + private function getQtyInStockBySku($sku) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/' . self::SERVICE_STOCK_ITEMS_NAME . "/$sku", + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'catalogInventoryStockRegistryV1', + 'serviceVersion' => 'V1', + 'operation' => 'catalogInventoryStockRegistryV1GetStockItemBySku', + ], + ]; + $arguments = ['productSku' => $sku]; + $apiResult = $this->_webApiCall($serviceInfo, $arguments); + return $apiResult['qty']; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php index 81a6c545e0cb8..f5a6413457eff 100644 --- a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php @@ -1,7 +1,7 @@ +## Allow access to command.php, website.php, export.php, pathChecker.php, deleteMagentoGeneratedCode.php and log.php + order allow,deny allow from all diff --git a/dev/tests/functional/bootstrap.php b/dev/tests/functional/bootstrap.php index 72dc6bf208cd0..f35114219616f 100644 --- a/dev/tests/functional/bootstrap.php +++ b/dev/tests/functional/bootstrap.php @@ -1,6 +1,6 @@ addClassMap($mtfComposerAutoload->getClassMap()); +} else { + $composerAutoloader = include $vendorAutoload; +} setCustomErrorHandler(); diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json index 936c4b968af3b..ffdc5743ba860 100644 --- a/dev/tests/functional/composer.json +++ b/dev/tests/functional/composer.json @@ -1,8 +1,8 @@ { "require": { - "magento/mtf": "1.0.0-rc47", - "php": "~5.6.0|7.0.2|~7.0.6", - "phpunit/phpunit": "4.1.0", + "magento/mtf": "1.0.0-rc53", + "php": "~5.6.5|7.0.2|~7.0.6", + "phpunit/phpunit": "~4.8.0|~5.5.0", "phpunit/phpunit-selenium": ">=1.2" }, "suggest": { diff --git a/dev/tests/functional/credentials.xml.dist b/dev/tests/functional/credentials.xml.dist index 3c61630fb148d..5e70e00f5b38e 100644 --- a/dev/tests/functional/credentials.xml.dist +++ b/dev/tests/functional/credentials.xml.dist @@ -1,7 +1,7 @@ @@ -27,4 +27,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/etc/config.xml.dist b/dev/tests/functional/etc/config.xml.dist index 91916f8be34da..d98e297152c84 100644 --- a/dev/tests/functional/etc/config.xml.dist +++ b/dev/tests/functional/etc/config.xml.dist @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/etc/config.xsd b/dev/tests/functional/etc/config.xsd index 0b4c147d95541..cf0cec7467e33 100644 --- a/dev/tests/functional/etc/config.xsd +++ b/dev/tests/functional/etc/config.xsd @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/etc/di.xml b/dev/tests/functional/etc/di.xml index 69951a2cc1b86..575471d34f5ff 100644 --- a/dev/tests/functional/etc/di.xml +++ b/dev/tests/functional/etc/di.xml @@ -1,11 +1,17 @@ + + + + + + etc/config.xsd @@ -13,4 +19,100 @@ + + + + + Magento\Mtf\Troubleshooting\StorefrontAnalyzer + Magento\Mtf\Troubleshooting\PhpUnitAnalyzer + Magento\Mtf\Troubleshooting\AdminAnalyzer + Magento\Mtf\Troubleshooting\Configuration + Magento\Mtf\Troubleshooting\SeleniumSessionAnalyzer + Magento\Mtf\Troubleshooting\StaticClassesGenerator + Magento\Mtf\Troubleshooting\ConfigAnalyzer + Magento\Mtf\Troubleshooting\HtaccessAnalyzer + Magento\Mtf\Troubleshooting\GlobalAnalyzer + + + + + + + + Magento\Mtf\Troubleshooting\PhpUnitAnalyzer + Magento\Mtf\Troubleshooting\StorefrontAnalyzer + Magento\Mtf\Troubleshooting\ConfigAnalyzer + Magento\Mtf\Troubleshooting\AdminAnalyzer + Magento\Mtf\Troubleshooting\Configuration + Magento\Mtf\Troubleshooting\HtaccessAnalyzer + Magento\Mtf\Troubleshooting\StaticClassesGenerator + Magento\Mtf\Troubleshooting\SeleniumSessionAnalyzer + + + + + + + Magento\Mtf\Util\Troubleshooting\GlobalConfig + Magento\Mtf\Util\Troubleshooting\GlobalConfigDist + + + + + + Magento\Mtf\Config\FileResolver\Primary + Magento\Mtf\Config\Converter + Magento\Mtf\Config\SchemaLocator\Config + + scope + name + + config.xml + etc + + + + + + Magento\Mtf\Util\Troubleshooting\Config + + + + + + Magento\Mtf\Config\FileResolver\ScopeConfig + Magento\Mtf\Config\Converter + Magento\Mtf\Config\SchemaLocator\Config + + scope + name + + config.xml.dist + etc + + + + + + Magento\Mtf\Util\Troubleshooting\ConfigDist + + + + + + \w*?\.csv + + + + + + catalog_product.*?\.csv + + + + + + customer.*?\.csv + + diff --git a/dev/tests/functional/etc/events.xml b/dev/tests/functional/etc/events.xml index a2648835265dd..7417f8d693108 100644 --- a/dev/tests/functional/etc/events.xml +++ b/dev/tests/functional/etc/events.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/etc/events.xsd b/dev/tests/functional/etc/events.xsd index cb8bec4e31fa4..8c6fedcf413f0 100644 --- a/dev/tests/functional/etc/events.xsd +++ b/dev/tests/functional/etc/events.xsd @@ -3,7 +3,7 @@ /** * This schema must be used to validate events.xml files * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -75,4 +75,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/etc/repository_replacer.xml b/dev/tests/functional/etc/repository_replacer.xml index 61046fbac44c4..e87bfc5fed30b 100644 --- a/dev/tests/functional/etc/repository_replacer.xml +++ b/dev/tests/functional/etc/repository_replacer.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/etc/repository_replacer_payments.xml b/dev/tests/functional/etc/repository_replacer_payments.xml new file mode 100644 index 0000000000000..6b9b9fe54515f --- /dev/null +++ b/dev/tests/functional/etc/repository_replacer_payments.xml @@ -0,0 +1,17 @@ + + + + + + BRAINTREEE_ENVIRONMENT + BRAINTREEE_MERCHANT_ID + BRAINTREE_PUBLIC_KEY + BRAINTREE_PRIVATE_KEY + + + diff --git a/dev/tests/functional/isolation.php b/dev/tests/functional/isolation.php index 11a04b573baf9..9b5c9e7f2e633 100644 --- a/dev/tests/functional/isolation.php +++ b/dev/tests/functional/isolation.php @@ -1,6 +1,6 @@ objectManager = $objectManager; + $this->arguments = $arguments; + } + /** * @inheritdoc */ public function apply() { + foreach ($this->arguments as $argument) { + $handler = $this->objectManager->get($argument); + $handler->execute($this); + } if ($this->isCleanInstance) { $this->clearInstance(); } diff --git a/dev/tests/functional/lib/Magento/Mtf/App/State/State1.php b/dev/tests/functional/lib/Magento/Mtf/App/State/State1.php index 8005f4bff16f7..cb93d4eb2c1d7 100644 --- a/dev/tests/functional/lib/Magento/Mtf/App/State/State1.php +++ b/dev/tests/functional/lib/Magento/Mtf/App/State/State1.php @@ -1,12 +1,14 @@ objectManager = $objectManager; + $this->curlTransport = $curlTransport; } /** @@ -44,7 +59,9 @@ public function __construct(ObjectManager $objectManager) public function apply() { parent::apply(); - if (file_exists(dirname(dirname(dirname(MTF_BP))) . '/app/etc/config.php')) { + $this->curlTransport->write($_ENV['app_frontend_url'], [], CurlInterface::GET); + $response = $this->curlTransport->read(); + if (strpos($response, 'Home Page') !== false) { $this->objectManager->create( \Magento\Config\Test\TestStep\SetupConfigurationStep::class, ['configData' => $this->config] diff --git a/dev/tests/functional/lib/Magento/Mtf/App/State/StateHandlerInterface.php b/dev/tests/functional/lib/Magento/Mtf/App/State/StateHandlerInterface.php new file mode 100644 index 0000000000000..564299ee8ec76 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/App/State/StateHandlerInterface.php @@ -0,0 +1,21 @@ +eventManager->dispatchEvent(['set_value'], [__METHOD__, $this->getAbsoluteSelector()]); - + $this->clear(); $conditions = $this->decodeValue($value); $context = $this->find($this->mainCondition, Locator::SELECTOR_XPATH); - $this->clear(); + if (!empty($conditions[0]['TopLevelCondition'])) { + array_unshift($this->mapParams, 'aggregator'); + $condition = $this->parseTopLevelCondition($conditions[0]['TopLevelCondition']); + $this->fillCondition($condition['rules'], $context); + unset($conditions[0]); + array_shift($this->mapParams); + } $this->addMultipleCondition($conditions, $context); } @@ -430,7 +438,6 @@ protected function decodeValue($value) $value = preg_replace('/\[([^\[{])/', '"$1', $value); $value = preg_replace('/([^\]}])\]/', '$1"', $value); $value = str_replace(array_keys($this->decodeChars), $this->decodeChars, $value); - $value = "[{$value}]"; $value = json_decode($value, true); if (null === $value) { @@ -461,6 +468,24 @@ protected function parseCondition($condition) ]; } + /** + * Parse top level condition. + * + * @param string $condition + * @return array + * @throws \Exception + */ + protected function parseTopLevelCondition($condition) + { + if (preg_match_all('/([^|]+)\|?/', $condition, $match) === false) { + throw new \Exception('Bad format condition'); + } + + return [ + 'rules' => $match[1], + ]; + } + /** * Find next param of condition for fill. * @@ -496,6 +521,7 @@ protected function resetKeyParam() * Param wait loader. * * @param ElementInterface $element + * @return void */ protected function waitForCondition(ElementInterface $element) { diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php index e09ca5647cf59..663c61d84d311 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php +++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DatepickerElement.php @@ -1,6 +1,6 @@ find($this->datePickerButton, Locator::SELECTOR_XPATH)->click(); $datapicker = $this->find($this->datePickerBlock, Locator::SELECTOR_XPATH); - $datapicker->find($this->datePickerMonth, Locator::SELECTOR_XPATH, 'select')->setValue($date[0]); $datapicker->find($this->datePickerYear, Locator::SELECTOR_XPATH, 'select')->setValue($date[2]); + $datapicker->find($this->datePickerMonth, Locator::SELECTOR_XPATH, 'select')->setValue($date[0]); $datapicker->find(sprintf($this->datePickerCalendar, $date[1]), Locator::SELECTOR_XPATH)->click(); if ($datapicker->isVisible()) { $datapicker->find($this->datePickerButtonClose, Locator::SELECTOR_XPATH)->click(); diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php index 9d03e7553329d..b5e055af16247 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php +++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/DropdownmultiselectElement.php @@ -1,6 +1,6 @@ optionMaskFollowing, $optionSelector) . '/a'; - $option = $this->driver->find($optionSelector, Locator::SELECTOR_XPATH); + $option = $this->context->find($optionSelector, Locator::SELECTOR_XPATH); if (!$option->isVisible()) { throw new \Exception('[' . implode('/', $value) . '] option is not visible in store switcher.'); } diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php index f179d7d905340..4f2acd3ec54fd 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php +++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/MultiselectgrouplistElement.php @@ -1,6 +1,6 @@ eventManager->dispatchEvent(['get_value'], [$this->getAbsoluteSelector()]); + + return $this->find($this->selectedLabelSelector)->getText(); + } + + /** + * Select radio button based on label value. + * + * @param string $value + * @return void + */ + public function setValue($value) + { + $this->eventManager->dispatchEvent(['set_value'], [__METHOD__, $this->getAbsoluteSelector()]); + + $radioButtonLabel = $this->find(sprintf($this->labelSelector, $value), Locator::SELECTOR_XPATH); + if (!$this->isSelected()) { + $radioButtonLabel->click(); + } + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/SelectstoreElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/SelectstoreElement.php index 0abccf6fa7b84..1316bda74982c 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/SelectstoreElement.php +++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/SelectstoreElement.php @@ -1,6 +1,6 @@ keys([$value]); $searchedItem = $this->find(sprintf($this->resultItem, $value), Locator::SELECTOR_XPATH); + $searchedCountElements = $this->find($this->searchedCount); + $this->waitUntil( + function () use ($searchedCountElements) { + return $searchedCountElements->isVisible() ? true : null; + } + ); $searchedItem->click(); $closeButton = $this->find($this->closeButton); if ($closeButton->isVisible()) { diff --git a/dev/tests/functional/lib/Magento/Mtf/Client/Element/SwitcherElement.php b/dev/tests/functional/lib/Magento/Mtf/Client/Element/SwitcherElement.php index 23059ebceb3b2..1b4413164600f 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Client/Element/SwitcherElement.php +++ b/dev/tests/functional/lib/Magento/Mtf/Client/Element/SwitcherElement.php @@ -1,6 +1,6 @@ [ * 'options' => [ diff --git a/dev/tests/functional/lib/Magento/Mtf/EntryPoint/EntryPoint.php b/dev/tests/functional/lib/Magento/Mtf/EntryPoint/EntryPoint.php index 20ee661fe48dc..781d75b7a8817 100644 --- a/dev/tests/functional/lib/Magento/Mtf/EntryPoint/EntryPoint.php +++ b/dev/tests/functional/lib/Magento/Mtf/EntryPoint/EntryPoint.php @@ -1,6 +1,6 @@ objectManager = $objectManager; + $this->urlAnalyzer = $urlAnalyzer; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:check-magento-admin') + ->setDescription('Check that app_backend_url is correct and admin can log in to Admin.'); + } + + /** + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + \PHPUnit_Util_Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); + $this->output = $this->objectManager->create( + \Magento\Mtf\Console\Output::class, + ['output' => $output] + ); + $this->output->writeln("Verifying Magento Admin..."); + $adminUrlAnalyzerMessages = $this->runAdminUrlAnalyzer(); + if (isset($adminUrlAnalyzerMessages['error']) === false) { + $this->output->outputMessages($this->urlAnalyzer->checkDomain($_ENV['app_backend_url'])); + } else { + $this->output->outputMessages($adminUrlAnalyzerMessages); + } + $this->output->writeln("Admin verification finished."); + } + + /** + * Execute Admin url analyzer check. + * + * @return null|array + */ + public function runAdminUrlAnalyzer() + { + if (!isset($_ENV['app_backend_url'])) { + $messages['error'][] = 'app_backend_url parameter is absent in the phpunit.xml file. ' + . 'Please, copy parameter from phpunit.xml.dist.'; + return $messages; + } + $this->output->outputMessages($this->urlAnalyzer->fixLastSlash('app_backend_url')); + $url1 = $_ENV['app_backend_url']; + if (strpos($url1, '/index.php') !== false) { + $url2 = str_replace('/index.php', '', $url1); + } else { + $pattern = '/(\/\w+\/)$/'; + $replacement = '/index.php$1'; + $url2 = str_replace($url1, preg_replace($pattern, $replacement, $url1), $url1); + } + $urls = [$url1, $url2]; + $isUrlValid = false; + foreach ($urls as $url) { + $_ENV['app_backend_url'] = $url; + try { + $config = \Magento\Mtf\ObjectManagerFactory::getObjectManager()->create( + \Magento\Mtf\Config\DataInterface::class + ); + $curl = new BackendDecorator(new CurlTransport(), $config); + $response = $curl->read(); + if (strpos($response, '404') !== false) { + break; + } + $curl->close(); + $isUrlValid = true; + break; + } catch (\Exception $e) { + continue; + } + } + if ($isUrlValid == false) { + $messages['error'][] = 'Check correctness of app_backend_url in phpunit.xml.'; + return $messages; + } elseif ($url1 != $_ENV['app_backend_url']) { + return $this->urlAnalyzer->resolveIndexPhpProblem($_ENV['app_backend_url']); + } + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/ConfigAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/ConfigAnalyzer.php new file mode 100644 index 0000000000000..b7ee868eb22d7 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/ConfigAnalyzer.php @@ -0,0 +1,140 @@ +objectManager = $objectManager; + $this->configXml = $configXml->get(); + $this->configXmlDist = $configXmlDist->get(); + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:check-config-valid') + ->setDescription('Check if config.xml is configured properly.'); + } + + /** + * Execute check if config.xml is configured properly. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $output = $this->objectManager->create( + \Magento\Mtf\Console\Output::class, + ['output' => $output] + ); + $output->writeln("Checking config.xml file configuration..."); + $output->outputMessages($this->checkConfigFileAvailable()); + $output->writeln("config.xml file check is finished."); + } + + /** + * Check if config.xml file is present in MTF_BP/etc folder. + * + * @return array + */ + private function checkConfigFileAvailable() + { + $messages = []; + $configFileExists = false; + if (file_exists($this->configFilePath)) { + $configFileExists = true; + if ($this->recursiveKeys($this->configXml) != $this->recursiveKeys($this->configXmlDist)) { + $messages['error'][] = 'Check your config.xml file to contain all configs from config.xml.dist.'; + } + } else { + if (file_exists($this->configFilePath . '.dist')) { + if (!copy($this->configFilePath . '.dist', $this->configFilePath)) { + $messages['error'][] = 'Failed to copy config.xml.dist to config.xml.'; + return $messages; + } + $messages['info'][] = 'config.xml file has been created based on config.xml.dist.'; + $configFileExists = true; + } + } + if (!$configFileExists) { + $messages['error'][] = 'Cannot define config.xml configuration path.'; + } + return $messages; + } + + /** + * Get array of array keys. + * + * @param array $input + * @return array + */ + private function recursiveKeys(array $input) + { + $output = array_keys($input); + foreach ($input as $sub) { + if (is_array($sub)) { + $output = array_merge($output, $this->recursiveKeys($sub)); + } + } + return $output; + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/Configuration.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/Configuration.php new file mode 100644 index 0000000000000..271c21154d3a4 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/Configuration.php @@ -0,0 +1,80 @@ +objectManager = $objectManager; + $this->state1 = $state1; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:apply-magento-configuration') + ->setDescription('Apply proper Magento configuration to run functional tests.'); + } + + /** + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $output = $this->objectManager->create( + \Magento\Mtf\Console\Output::class, + ['output' => $output] + ); + $output->writeln("Applying Magento configuration..."); + $this->state1->apply(); + $output->outputMessages( + ['info' => ['Magento configuration was updated in order to run functional tests without errors ' + . '(disabled WYSIWYG, enabled admin account sharing etc.).'] + ] + ); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/GlobalAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/GlobalAnalyzer.php new file mode 100644 index 0000000000000..3ed93ac7351dd --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/GlobalAnalyzer.php @@ -0,0 +1,61 @@ +commandList = $commandList; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:check-all') + ->setDescription('Perform all available checks.'); + } + + /** + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + foreach ($this->commandList as $command) { + $command->execute($input, $output); + $output->writeln(''); + } + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/Helper/UrlAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/Helper/UrlAnalyzer.php new file mode 100644 index 0000000000000..e419ae6e0089d --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/Helper/UrlAnalyzer.php @@ -0,0 +1,70 @@ + ['"app_backend_url" has been updated in the phpunit.xml.']]; + } + + /** + * Check if url has subdomains. + * + * @param string $url + * @return array + */ + public function checkDomain($url) + { + $messages = []; + $pattern = '/([-%\w]*?\.\w+)/'; + if (preg_match($pattern, $url) === false) { + $messages['error'][] = + 'Instance should have domain name with at least one subdomain to function correctly. Examples:' + . PHP_EOL . "\tValid: http://magento.dev/, https://mage.local/." + . PHP_EOL . "\tInvalid: http://localhost/, https://magento/."; + } + + return $messages; + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/HtaccessAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/HtaccessAnalyzer.php new file mode 100644 index 0000000000000..82d79a8a821c6 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/HtaccessAnalyzer.php @@ -0,0 +1,97 @@ +objectManager = $objectManager; + $this->curl = $curl; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:check-htaccess') + ->setDescription('Check .htaccess file is present. It is needed to run cli commands via browser url.'); + } + + /** + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + \PHPUnit_Util_Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); + $output = $this->objectManager->create( + \Magento\Mtf\Console\Output::class, + ['output' => $output] + ); + try { + $output->writeln("Checking .htaccess file..."); + $this->curl->write($_ENV['app_frontend_url'] . $this->commandPath, [], CurlInterface::GET); + $this->curl->read(); + $responseCode = $this->curl->getInfo(CURLINFO_HTTP_CODE); + if ($responseCode != 200) { + $message['error'][] = 'Your .htaccess file doesn\'t exist. ' + . 'Please, create it from to .htaccess.sample.'; + $output->outputMessages($message); + } + $this->curl->close(); + } catch (\Exception $e) { + $output->outputMessages(['error' => [$e->getMessage()]]); + } + $output->writeln(".htaccess check finished."); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/PhpUnitAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/PhpUnitAnalyzer.php new file mode 100644 index 0000000000000..2b1208834ff10 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/PhpUnitAnalyzer.php @@ -0,0 +1,82 @@ +objectManager = $objectManager; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:check-phpunit-config-file') + ->setDescription('Check if phpunit file is available.'); + } + + /** + * Execute command for checkout phpunit.xml config file availability. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $output = $this->objectManager->create( + \Magento\Mtf\Console\Output::class, + ['output' => $output] + ); + $output->writeln("Checking phpunit.xml file availability..."); + $messages = []; + $configFileExists = false; + if (file_exists(MTF_PHPUNIT_FILE)) { + $configFileExists = true; + } else { + if (file_exists(MTF_PHPUNIT_FILE . '.dist')) { + if (!copy(MTF_PHPUNIT_FILE . '.dist', MTF_PHPUNIT_FILE)) { + $messages['error'][] = 'Failed to copy phpunit.xml.dist to phpunit.xml.'; + } else { + $messages['info'][] = 'phpunit.xml file has been created based on phpunit.xml.dist. ' + . 'Please, adjust your PHPUnit configuration to use new file.'; + $configFileExists = true; + } + } + } + if (!$configFileExists) { + $messages['error'][] = 'Cannot define phpunit configuration path.'; + } + $output->outputMessages($messages); + $output->writeln("phpunit.xml check finished."); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/SeleniumSessionAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/SeleniumSessionAnalyzer.php new file mode 100644 index 0000000000000..90ad051223a23 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/SeleniumSessionAnalyzer.php @@ -0,0 +1,79 @@ +objectManager = $objectManager; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:check-selenium-session-connection') + ->setDescription('Check that Selenium session connection is established.'); + } + + /** + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $output = $this->objectManager->create( + \Magento\Mtf\Console\Output::class, + ['output' => $output] + ); + $output->writeln("Verifying selenium server session..."); + try { + $driver = $this->objectManager->create(Driver::class); + $driver->closeWindow(); + } catch (\Exception $e) { + $output->outputMessages(['error' => + [ + 'The Selenium Server session cannot be established. Check if:' + . PHP_EOL . "\tSelenium server is launched." + . PHP_EOL . "\tSelenium server host and port configuration are correct in etc/config.xml." + . PHP_EOL . "\tThere is a valid browser name in etc/config.xml." + . PHP_EOL . "\tSelenium server is run with appropriate driver." + . PHP_EOL . "\tSelenium server version is compatible with web browser version." + ] + ]); + } + $output->writeln('Verification of selenium server session is finished.'); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StaticClassesGenerator.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StaticClassesGenerator.php new file mode 100644 index 0000000000000..a6ab99be28be6 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StaticClassesGenerator.php @@ -0,0 +1,68 @@ +objectManager = $objectManager; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:generate-static-classes') + ->setDescription('Generate static classes (Blocks, Pages, Repositories etc.).'); + } + + /** + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $output = $this->objectManager->create( + Output::class, + ['output' => $output] + ); + $output->writeln("Generating static classes..."); + exec('php ' . MTF_BP . DIRECTORY_SEPARATOR . 'utils' . DIRECTORY_SEPARATOR . 'generate.php', $error, $exitCode); + if ($exitCode) { + $output->outputMessages(['error' => $error]); + } + $output->writeln('Static classes generation is finished.'); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StorefrontAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StorefrontAnalyzer.php new file mode 100644 index 0000000000000..07f9748719b56 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StorefrontAnalyzer.php @@ -0,0 +1,123 @@ +objectManager = $objectManager; + $this->urlAnalyzer = $urlAnalyzer; + $this->curlTransport = $curlTransport; + } + + /** + * Configure command. + * + * @return void + */ + protected function configure() + { + parent::configure(); + $this->setName('troubleshooting:check-magento-storefront') + ->setDescription('Check that app_frontend_url config is correct and Magento installed.'); + } + + /** + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + \PHPUnit_Util_Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); + $output = $this->objectManager->create( + \Magento\Mtf\Console\Output::class, + ['output' => $output] + ); + $output->writeln("Verifying Magento Storefront..."); + $storefrontUrlAnalyzerMessages = $this->runStorefrontUrlAnalyzer(); + if (isset($storefrontUrlAnalyzerMessages['error']) === false) { + $output->outputMessages($this->urlAnalyzer->fixLastSlash('app_frontend_url')); + $output->outputMessages($this->urlAnalyzer->checkDomain($_ENV['app_frontend_url'])); + } else { + $output->outputMessages($storefrontUrlAnalyzerMessages); + } + $output->writeln("Storefront verification finished."); + } + + /** + * Run Storefront url analyzer check. + * + * @return array + */ + private function runStorefrontUrlAnalyzer() + { + $messages = []; + if (!isset($_ENV['app_frontend_url'])) { + $messages['error'][] = 'app_frontend_url parameter is absent in the phpunit.xml file. ' + . 'Please, copy file from phpunit.xml.dist.'; + return $messages; + } + $url = $_ENV['app_frontend_url']; + try { + $this->curlTransport->write($url, [], CurlInterface::GET); + $response = $this->curlTransport->read(); + if (strpos($response, 'Home Page') === false) { + $messages['error'][] = 'Magento seems not installed. Check your Magento instance.'; + } + } catch (\Exception $e) { + $messages['error'][] = $e->getMessage(); + } + $this->curlTransport->close(); + + return $messages; + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php index 96be468a6eb37..350c9585d15fd 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php @@ -1,13 +1,12 @@ /dev/null &'); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Setup.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Setup.php new file mode 100644 index 0000000000000..5f5fe66d96cef --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Setup.php @@ -0,0 +1,52 @@ +options); + } + + /** + * DI Compile. + * + * @return void + */ + public function diCompile() + { + parent::execute(Setup::PARAM_SETUP_DI_COMPILE); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/StaticContent.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/StaticContent.php new file mode 100644 index 0000000000000..225b99b0283f6 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/StaticContent.php @@ -0,0 +1,30 @@ +objectManager = $objectManager; + $this->reader = $this->getReader($type); + } + + /** + * Get reader for export files. + * + * @param string $type + * @return ReaderInterface + * @throws \ReflectionException + */ + private function getReader($type) + { + $readerPath = sprintf($this->readerPath, ucfirst($type)); + try { + return $this->objectManager->create($readerPath); + } catch (\ReflectionException $e) { + throw new \ReflectionException("Virtual type '$readerPath' does not exist. Please, check it in di.xml."); + } + } + + /** + * Get the export file by name. + * + * @param string $name + * @return Data|null + */ + public function getByName($name) + { + $this->reader->getData(); + foreach ($this->reader->getData() as $file) { + if ($file->getName() === $name) { + return $file; + } + } + + return null; + } + + /** + * Get latest created the export file. + * + * @return Data|null + */ + public function getLatest() + { + $max = 0; + $latest = null; + foreach ($this->reader->getData() as $file) { + if ($file->getDate() > $max) { + $max = $file->getDate(); + $latest = $file; + } + } + + return $latest; + } + + /** + * Get all export files by date range using unix time stamp. + * + * @param string $start + * @param string $end + * @return Data[] + */ + public function getByDateRange($start, $end) + { + $files = []; + foreach ($this->reader->getData() as $file) { + if ($file->getDate() > $start && $file->getDate() < $end) { + $files[] = $file; + } + } + + return $files; + } + + /** + * Get all export files. + * + * @return Data[] + */ + public function getAll() + { + return $this->reader->getData(); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Data.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Data.php new file mode 100644 index 0000000000000..3cc9b5199ff72 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Data.php @@ -0,0 +1,58 @@ +data = $data; + } + + /** + * Get file name. + * + * @return string + */ + public function getName() + { + return $this->data['name']; + } + + /** + * Get file content. + * + * @return string + */ + public function getContent() + { + return $this->data['content']; + } + + /** + * Get file creation date. + * + * @return string + */ + public function getDate() + { + return $this->data['date']; + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Reader.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Reader.php new file mode 100644 index 0000000000000..e75c23b2f6993 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Reader.php @@ -0,0 +1,89 @@ +objectManager = $objectManager; + $this->template = $template; + $this->transport = $transport; + } + + /** + * Exporting files as Data object from Magento. + * + * @return Data[] + */ + public function getData() + { + $data = []; + foreach ($this->getFiles() as $file) { + $data[] = $this->objectManager->create(Data::class, ['data' => $file]); + } + + return $data; + } + + /** + * Get files by template from the Magento. + * + * @return array + */ + private function getFiles() + { + $this->transport->write($this->prepareUrl(), [], CurlInterface::GET); + $serializedFiles = $this->transport->read(); + $this->transport->close(); + + return unserialize($serializedFiles); + } + + /** + * Prepare url. + * + * @return string + */ + private function prepareUrl() + { + return $_ENV['app_frontend_url'] . self::URL . '?template=' . urlencode($this->template); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/ReaderInterface.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/ReaderInterface.php new file mode 100644 index 0000000000000..a16d1f6081e7b --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/ReaderInterface.php @@ -0,0 +1,25 @@ +transport = $transport; + } + + /** + * Get content of log file in var/log folder by file name. + * + * @param string $name + * @return array + */ + public function getFileContent($name) + { + $curl = $this->transport; + $curl->write($this->prepareUrl($name), [], CurlTransport::GET); + $data = $curl->read(); + $curl->close(); + + return unserialize($data); + } + + /** + * Prepare url. + * + * @param string $name + * @return string + */ + private function prepareUrl($name) + { + return $_ENV['app_frontend_url'] . self::URL . '?name=' . urlencode($name); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/GeneratedCode.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/GeneratedCode.php new file mode 100644 index 0000000000000..c82231a9e38f1 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/GeneratedCode.php @@ -0,0 +1,49 @@ +transport = $transport; + } + + /** + * Remove generated code. + * + * @return void + */ + public function delete() + { + $url = $_ENV['app_frontend_url'] . self::URL; + $curl = $this->transport; + $curl->write($url, [], CurlInterface::GET); + $curl->read(); + $curl->close(); + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/PathChecker.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/PathChecker.php new file mode 100644 index 0000000000000..f61210dc554ef --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/PathChecker.php @@ -0,0 +1,52 @@ +transport = $transport; + } + + /** + * Check that $path exists. + * + * @param string $path + * @return bool + */ + public function pathExists($path) + { + $url = $_ENV['app_frontend_url'] . self::URL . '?path=' . urlencode($path); + $curl = $this->transport; + $curl->write($url, [], CurlInterface::GET); + $result = $curl->read(); + $curl->close(); + + return strpos($result, 'path exists: true') !== false; + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php index 611f46894c8bc..b8ef09eae13f5 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Repository/RepositoryResource.php b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Repository/RepositoryResource.php index bca30a9d44335..d8db74e0ecbe2 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Repository/RepositoryResource.php +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Repository/RepositoryResource.php @@ -1,6 +1,6 @@ @@ -39,6 +39,7 @@ + diff --git a/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php index f9cd7d34e2a1e..f63263a504cb7 100644 --- a/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php +++ b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php new file mode 100644 index 0000000000000..fe06946857178 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php @@ -0,0 +1,55 @@ +configuration = $configuration; + } + + /** + * Cancel subscription for functional tests + * + * @param AbstractState $state + * @return bool + * @throws \Exception + */ + public function execute(AbstractState $state) + { + $url = $_ENV['app_backend_url'] . 'analytics/subscription/postpone'; + $curl = new BackendDecorator(new CurlTransport(), $this->configuration); + $curl->write($url, []); + $response = $curl->read(); + $curl->close(); + if (isset($response['success'])) { + return $response['success']; + } + return false; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/Analytics/SubscriptionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/Analytics/SubscriptionBlock.php new file mode 100644 index 0000000000000..f213f9278dbae --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/Analytics/SubscriptionBlock.php @@ -0,0 +1,42 @@ +_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('Yes'); + } + + /** + * Disable checkbox in modal window. + * + * @return void + */ + public function disableCheckbox() + { + $this->_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('No'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php new file mode 100644 index 0000000000000..500b06d1e8d08 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php @@ -0,0 +1,63 @@ +_rootElement->find($this->analyticsStatus, Locator::SELECTOR_CSS)->getValue(); + } + + /** + * @return array|string + */ + public function enableAnalytics() + { + return $this->_rootElement->find($this->analyticsStatus, Locator::SELECTOR_CSS, 'select')->setValue('Yes'); + } + + /** + * @return array|string + */ + public function saveConfig() + { + return $this->browser->find($this->submitButton)->click(); + } + + /** + * @return array|string + */ + public function getAnalyticsStatus() + { + return $this->_rootElement->find($this->analyticsStatusLabel, Locator::SELECTOR_CSS)->getText(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php new file mode 100644 index 0000000000000..8273ddfebc1b6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -0,0 +1,39 @@ +Configuration>General>Analytics->General menu. + */ +class AssertConfigAnalyticsDisabled extends AbstractConstraint +{ + /** + * Assert Analytics is disabled in Stores > Configuration > General > Analytics menu. + * + * @param ConfigAnalytics $configAnalytics + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics) + { + \PHPUnit_Framework_Assert::assertFalse( + (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), + 'Magento Analytics is enabled' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics is disabled in Stores > Configuration > General > Analytics > General menu.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php new file mode 100644 index 0000000000000..03f24b47ca2c0 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -0,0 +1,37 @@ + Configuration > General > Analytics > General menu. + */ +class AssertConfigAnalyticsEnabled extends AbstractConstraint +{ + /** + * Assert Analytics is enabled in Stores > Configuration > General > Analytics menu. + * @param ConfigAnalytics $configAnalytics + */ + public function processAssert(ConfigAnalytics $configAnalytics) + { + \PHPUnit_Framework_Assert::assertTrue( + (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), + 'Magento Analytics is disabled' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics is enabled in Stores > Configuration > General > Analytics > General menu.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsStatusDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsStatusDisabled.php new file mode 100644 index 0000000000000..c290592a2d124 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsStatusDisabled.php @@ -0,0 +1,38 @@ + Configuration > General > Analytics > General menu. + */ +class AssertConfigAnalyticsStatusDisabled extends AbstractConstraint +{ + /** + * Assert Analytics status is Disabled in Stores > Configuration > General > Analytics menu. + * @param ConfigAnalytics $configAnalytics + */ + public function processAssert(ConfigAnalytics $configAnalytics) + { + \PHPUnit_Framework_Assert::assertEquals( + $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), + 'Subscription status: Disabled', + 'Magento Analytics status is not disabled' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics status is disabled in Stores > Configuration > General > Analytics > General menu.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsStatusPending.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsStatusPending.php new file mode 100644 index 0000000000000..121beba6a2f34 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsStatusPending.php @@ -0,0 +1,38 @@ + Configuration > General > Analytics > General menu. + */ +class AssertConfigAnalyticsStatusPending extends AbstractConstraint +{ + /** + * Assert Analytics status is Pending in Stores > Configuration > General > Analytics menu. + * @param ConfigAnalytics $configAnalytics + */ + public function processAssert(ConfigAnalytics $configAnalytics) + { + \PHPUnit_Framework_Assert::assertEquals( + $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), + 'Subscription status: Pending', + 'Magento Analytics status is not pending' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics status is pending in Stores > Configuration > General > Analytics > General menu.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php new file mode 100644 index 0000000000000..ae93e7a5ec4ca --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php @@ -0,0 +1,39 @@ +getSubscriptionBlock()->isVisible(), + "Subscription form is visible on dashboard." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Subscription form is absent on dashboard."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml new file mode 100644 index 0000000000000..9cefa67e91862 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml new file mode 100644 index 0000000000000..959db18cb3146 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml new file mode 100644 index 0000000000000..709a0dc4e2904 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml @@ -0,0 +1,19 @@ + + + + + + RoleName%isolation% + Custom + %current_password% + + Magento_Backend::dashboard + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml new file mode 100644 index 0000000000000..b2a4821b52942 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml @@ -0,0 +1,24 @@ + + + + + + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123q + 123123q + + role::role_without_subscription_permissions + + %current_password% + Active + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AcceptAnalyticsSubscriptionTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AcceptAnalyticsSubscriptionTest.php new file mode 100644 index 0000000000000..7bab97f40dc55 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AcceptAnalyticsSubscriptionTest.php @@ -0,0 +1,28 @@ +Configuration>General>Analytics->General + * + * @ZephyrId MAGETWO-63108 + */ +class AcceptAnalyticsSubscriptionTest extends Scenario +{ + /* tags */ + const MVP = 'no'; + /* end tags */ + + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AcceptAnalyticsSubscriptionTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AcceptAnalyticsSubscriptionTest.xml new file mode 100644 index 0000000000000..869a018175961 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AcceptAnalyticsSubscriptionTest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php new file mode 100644 index 0000000000000..532779928fde5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php @@ -0,0 +1,37 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml new file mode 100644 index 0000000000000..d0520183ba0c7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml @@ -0,0 +1,15 @@ + + + + + + custom_admin_with_role_without_subscription_permissions + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/DeclineAnalyticsSubscriptionTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/DeclineAnalyticsSubscriptionTest.php new file mode 100644 index 0000000000000..f711fc8964d60 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/DeclineAnalyticsSubscriptionTest.php @@ -0,0 +1,28 @@ +Configuration>General>Analytics->General + * + * @ZephyrId MAGETWO-63156 + */ +class DeclineAnalyticsSubscriptionTest extends Scenario +{ + /* tags */ + const MVP = 'no'; + /* end tags */ + + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/DeclineAnalyticsSubscriptionTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/DeclineAnalyticsSubscriptionTest.xml new file mode 100644 index 0000000000000..b41521c81c703 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/DeclineAnalyticsSubscriptionTest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/RestoreAnalyticsSubscriptionTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/RestoreAnalyticsSubscriptionTest.php new file mode 100644 index 0000000000000..99d6e9e7be3fe --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/RestoreAnalyticsSubscriptionTest.php @@ -0,0 +1,30 @@ + Configuration > General > Analytics > General + * 4. Set option "Send the system and transaction data to Magento Analytics service to Yes + * + * @ZephyrId MAGETWO-63196 + */ +class RestoreAnalyticsSubscriptionTest extends Scenario +{ + /* tags */ + const MVP = 'no'; + /* end tags */ + + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/RestoreAnalyticsSubscriptionTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/RestoreAnalyticsSubscriptionTest.xml new file mode 100644 index 0000000000000..c5442a8fc5953 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/RestoreAnalyticsSubscriptionTest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/AcceptSubscriptionStep.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/AcceptSubscriptionStep.php new file mode 100644 index 0000000000000..bee839a6dd7cc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/AcceptSubscriptionStep.php @@ -0,0 +1,46 @@ +dashboard = $dashboard; + } + + /** + * Skip Subscription step. + * + * @return void + */ + public function run() + { + $this->dashboard->open(); + $this->dashboard->getSubscriptionBlock()->enableCheckbox(); + $this->dashboard->getModalBlock()->acceptWarning(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/ConfigAnalyticsStep.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/ConfigAnalyticsStep.php new file mode 100644 index 0000000000000..b925f2d9e6b13 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/ConfigAnalyticsStep.php @@ -0,0 +1,41 @@ + Configuration > General > Analytics > General + */ +class ConfigAnalyticsStep implements TestStepInterface +{ + /** + * Analytics Config settings page. + * + * @var configAnalytics + */ + private $configAnalytics; + + /** + * @param ConfigAnalytics $configAnalytics + */ + public function __construct( + ConfigAnalytics $configAnalytics + ) { + $this->configAnalytics = $configAnalytics; + } + + /** + * Open Config Analytics settings menu. + * + * @return void + */ + public function run() + { + $this->configAnalytics->open(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/DeclineSubscriptionStep.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/DeclineSubscriptionStep.php new file mode 100644 index 0000000000000..82f6ebb0c593d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/DeclineSubscriptionStep.php @@ -0,0 +1,41 @@ +dashboard = $dashboard; + } + + /** + * Decline Subscription step + * + * @return void + */ + public function run() + { + $this->dashboard->open(); + $this->dashboard->getSubscriptionBlock()->enableCheckbox(); + $this->dashboard->getModalBlock()->dismissWarning(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/RestoreConfigAnalyticsStep.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/RestoreConfigAnalyticsStep.php new file mode 100644 index 0000000000000..1389b78628329 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/RestoreConfigAnalyticsStep.php @@ -0,0 +1,44 @@ + Configuration > General > Analytics > General + * + */ +class RestoreConfigAnalyticsStep implements TestStepInterface +{ + /** + * Analytics Config settings page. + * + * @var configAnalytics + */ + private $configAnalytics; + + /** + * @param ConfigAnalytics $configAnalytics + */ + public function __construct( + ConfigAnalytics $configAnalytics + ) { + $this->configAnalytics = $configAnalytics; + } + + /** + * Open Config Analytics settings menu and restore sending data to the Analytics + * + * @return void + */ + public function run() + { + $this->configAnalytics->open(); + $this->configAnalytics->getAnalyticsForm()->enableAnalytics(); + $this->configAnalytics->getAnalyticsForm()->saveConfig(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/SkipSubscriptionStep.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/SkipSubscriptionStep.php new file mode 100644 index 0000000000000..c27f3a9d668bf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/SkipSubscriptionStep.php @@ -0,0 +1,42 @@ +dashboard = $dashboard; + } + + /** + * Skip Subscription step + * + * @return void + */ + public function run() + { + $this->dashboard->open(); + $this->dashboard->getSubscriptionBlock()->disableCheckbox(); + $this->dashboard->getModalBlock()->dismissWarning(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml new file mode 100644 index 0000000000000..c9ffa0e055adf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -0,0 +1,21 @@ + + + + + + + Magento\Analytics\Mtf\App\State\NotificationTimeHandler + + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml new file mode 100644 index 0000000000000..f6c83a4994cc3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Block/Form/Cc.php b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Block/Form/Cc.php deleted file mode 100644 index 7918859e53715..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Block/Form/Cc.php +++ /dev/null @@ -1,18 +0,0 @@ - - - - payment - - - - select - - - select - - - - diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Fixture/CreditCardAuthorizenet.xml b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Fixture/CreditCardAuthorizenet.xml deleted file mode 100644 index 2777d09b4f163..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Fixture/CreditCardAuthorizenet.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/ConfigData.xml index 40c02b42482f7..98189928e86a0 100644 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -71,5 +71,37 @@ 0 + + + payment + 1 + + authorize_capture + + + + + payment + 1 + + authorize + + + + + payment + 1 + + authorize_capture + + + + + payment + 1 + + authorize + + diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml index c949d827b4879..93735dcbb29d5 100644 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/TestCase/OnePageCheckoutTest.xml @@ -1,32 +1,27 @@ - - + + catalogProductSimple::product_10_dollar default - US_address_1 - guest + login + US_address_1_without_email Flat Rate Fixed 15.00 - credit_card_authorizenet authorizenet_directpost - visa_authorizenet + visa_default authorizenet Processing - - No - Authorization - - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Admin/Login.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Admin/Login.php index 87c831d3a7a30..a5bcec6c947b1 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Admin/Login.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Admin/Login.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/StoreStats.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/StoreStats.php index 86bf71b524136..d8f38d6545806 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/StoreStats.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/StoreStats.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/Tab/Products.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/Tab/Products.php index ed20ea4232368..2a405813ffd7a 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/Tab/Products.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Dashboard/Tab/Products.php @@ -1,6 +1,6 @@ _rootElement->find($subMenuItem, Locator::SELECTOR_XPATH)->click(); $this->waitForElementNotVisible($subMenuSelector, Locator::SELECTOR_XPATH); } + + /** + * Check if menu item is visible. + * + * @param string $menuItem + * @return bool + */ + public function isMenuItemVisible($menuItem) + { + $menuChain = array_map('trim', explode('>', $menuItem)); + $mainMenu = $menuChain[0]; + $subMenu = isset($menuChain[1]) ? $menuChain[1] : null; + + $mainMenuElement = $this->_rootElement->find(sprintf($this->mainMenu, $mainMenu), Locator::SELECTOR_XPATH); + if (!$mainMenuElement->isVisible()) { + return false; + } + if ($subMenu === null) { + return true; + } + $mainMenuElement->click(); + + $subMenuSelector = sprintf($this->subMenu, $mainMenu); + $this->waitForElementVisible($subMenuSelector, Locator::SELECTOR_XPATH); + $subMenuItem = $subMenuSelector . sprintf($this->subMenuItem, $subMenu); + return $this->_rootElement->find($subMenuItem, Locator::SELECTOR_XPATH)->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Messages.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Messages.php index 9c8b0beee9162..bf5b5faacbd9d 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Messages.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Messages.php @@ -1,6 +1,6 @@ _rootElement - ->find($this->errorMessage, Locator::SELECTOR_CSS) - ->getText(); + $this->waitForElementVisible($this->errorMessage); + + return $this->_rootElement->find($this->errorMessage)->getText(); } /** @@ -166,6 +166,16 @@ public function assertErrorMessage() return $this->waitForElementVisible($this->errorMessage, Locator::SELECTOR_CSS); } + /** + * Check for success message. + * + * @return bool + */ + public function assertSuccessMessage() + { + return $this->waitForElementVisible($this->successMessage, Locator::SELECTOR_CSS); + } + /** * Check for notice message. * @@ -187,6 +197,24 @@ public function getNoticeMessage() return $this->_rootElement->find($this->noticeMessage)->getText(); } + /** + * Get all notice messages which are present on the page. + * + * @return array + */ + public function getNoticeMessages() + { + $this->waitForElementVisible($this->noticeMessage); + $elements = $this->_rootElement->getElements($this->noticeMessage); + + $messages = []; + foreach ($elements as $element) { + $messages[] = $element->getText(); + } + + return $messages; + } + /** * Get warning message which is present on the page. * diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Page/Error.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Page/Error.php index a1fb7e604e1a3..e7acd0ab946ce 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Page/Error.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/Page/Error.php @@ -1,6 +1,6 @@ _rootElement->find( + return $this->_rootElement->find( sprintf($this->field, $tabName, $groupName, $fieldName), Locator::SELECTOR_CSS )->isVisible(); } + + /** + * Check if a field is disabled in a given group. + * + * @param string $tabName + * @param string $groupName + * @param string $fieldName + * @return bool + */ + public function isFieldDisabled($tabName, $groupName, $fieldName) + { + return $this->_rootElement->find( + sprintf($this->field, $tabName, $groupName, $fieldName), + Locator::SELECTOR_CSS + )->isDisabled(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/PageActions.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/PageActions.php index 2d156ce6daa5c..12b2b711b7433 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/PageActions.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/PageActions.php @@ -2,7 +2,7 @@ /** * Config actions block * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Payments.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Payments.php index dc081dc5d261e..8643703599114 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Payments.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Config/Payments.php @@ -1,6 +1,6 @@ Settings > Configuration page. + */ +class Tabs extends Block +{ + /** + * Top tab selector. + * + * @var string + */ + private $topTab = ".//div[@role='tab' and *[contains(.,'%s')]]"; + + /** + * Selector of block with sub tabs. + * + * @var string + */ + private $subTabs = "./following-sibling::ul"; + + /** + * Selector of specific sub tab name. + * + * @var string + */ + private $subTabName = 'li a span'; + + /** + * Get list of sub tabs names of tab. + * + * @param string $tab + * @return array + */ + public function getSubTabsNames($tab) + { + $subTabsNames = []; + + $topTab = $this->_rootElement->find(sprintf($this->topTab, $tab), Locator::SELECTOR_XPATH); + $subTabsBlock = $topTab->find($this->subTabs, Locator::SELECTOR_XPATH); + + if (!$subTabsBlock->isVisible()) { + $topTab->click(); + } + + foreach ($subTabsBlock->getElements($this->subTabName) as $elements) { + $subTabsNames[] = $elements->getText(); + } + + return $subTabsNames; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Delete/Form.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Delete/Form.php index ec1f9731ada5e..d69199aae4533 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Delete/Form.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Delete/Form.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/GroupForm.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/GroupForm.php index ef4f816c0ff35..4bf49c3cfa5e3 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/GroupForm.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/GroupForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.php index 3aa4352265535..4f9d11f0d4366 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.php @@ -1,6 +1,6 @@ _rootElement->find(sprintf($this->store, $name), Locator::SELECTOR_XPATH)->isVisible(); } + + /** + * Select store view by name from dropdown + * + * @param string $name + * @return bool + */ + public function selectStore($name) + { + return $this->_rootElement->find($this->storeGroupId, Locator::SELECTOR_XPATH, 'optgroupselect') + ->setValue($name); + } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.xml index 0aea3252f1bfe..d59772a437554 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/StoreForm.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/WebsiteForm.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/WebsiteForm.php index 31060d3c89e94..e144fae0f1c55 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/WebsiteForm.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/Edit/Form/WebsiteForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/FormPageActions.php index b1ffa0e62dc42..900b4ae2813b4 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/FormPageActions.php @@ -1,6 +1,6 @@ getTabs()->getSubTabsNames('Advanced')), + 'Developer section should be hidden in production mode.' + ); + } else { + \PHPUnit_Framework_Assert::assertTrue( + in_array('Developer', $configEdit->getTabs()->getSubTabsNames('Advanced')), + 'Developer section should be not hidden in developer or default mode.' + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Developer section has correct visibility.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php index cb3583144a5c3..58e7525a79c47 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php @@ -1,6 +1,6 @@ browser = $browser; + $this->customer = $customer; + $this->customer->persist(); + + // Log in to Customer Account on Storefront to assert that http is used indeed. + $this->objectManager->create(LogInCustomerOnStorefront::class, ['customer' => $this->customer])->run(); + $this->assertUsedProtocol($this->unsecuredProtocol); + + // Log out from Customer Account on Storefront to assert that JS is deployed validly as a part of statics. + $this->objectManager->create(LogOutCustomerOnStorefront::class)->run(); + $this->assertUsedProtocol($this->unsecuredProtocol); + } + + /** + * Assert that specified protocol is used on current page. + * + * @param string $expectedProtocol + * @return void + */ + protected function assertUsedProtocol($expectedProtocol) + { + if (substr($expectedProtocol, -3) !== "://") { + $expectedProtocol .= '://'; + } + + \PHPUnit_Framework_Assert::assertStringStartsWith( + $expectedProtocol, + $this->browser->getUrl(), + "$expectedProtocol is not used." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Unsecured URLs are used for Storefront pages.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php index daee3ea88643d..d1847e58bc106 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php @@ -1,6 +1,6 @@ browser = $browser; + + // Open specified Admin page using Navigation Menu to assert that JS is deployed validly as a part of statics. + $adminDashboardPage->open()->getMenuBlock()->navigate($navMenuPath); + $this->assertUsedProtocol($this->securedProtocol); + $this->assertDirectHttpUnavailable(); + } + + /** + * Assert that specified protocol is used on current page. + * + * @param string $expectedProtocol + * @return void + */ + protected function assertUsedProtocol($expectedProtocol) + { + if (substr($expectedProtocol, -3) !== "://") { + $expectedProtocol .= '://'; + } + + \PHPUnit_Framework_Assert::assertStringStartsWith( + $expectedProtocol, + $this->browser->getUrl(), + "$expectedProtocol is not used." + ); + } + + /** + * Assert that Merchant is redirected to https if trying to access the page directly via http. + * + * @return void + */ + protected function assertDirectHttpUnavailable() + { + $fakeUrl = str_replace($this->securedProtocol, $this->unsecuredProtocol, $this->browser->getUrl()); + $this->browser->open($fakeUrl); + \PHPUnit_Framework_Assert::assertStringStartsWith( + $this->securedProtocol, + $this->browser->getUrl(), + 'Merchant is not redirected to https if tries to access the Admin panel page directly via http.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Secured URLs are used for Admin panel pages.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertLocaleCodeVisibility.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertLocaleCodeVisibility.php new file mode 100644 index 0000000000000..4c6512e34b06a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertLocaleCodeVisibility.php @@ -0,0 +1,46 @@ +getForm()->getGroup('general', 'locale')->isFieldDisabled('general', 'locale', 'code'), + 'Locale field should be disabled in production mode.' + ); + } else { + \PHPUnit_Framework_Assert::assertFalse( + $configEdit->getForm()->getGroup('general', 'locale')->isFieldDisabled('general', 'locale', 'code'), + 'Locale field should be not disabled in developer or default mode.' + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Locale field has correct visibility.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertMenuItemNotVisible.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertMenuItemNotVisible.php new file mode 100644 index 0000000000000..73200a45272a2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertMenuItemNotVisible.php @@ -0,0 +1,43 @@ +open(); + + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getMenuBlock()->isMenuItemVisible($menuItem), + 'Menu item ' . $menuItem . ' is supposed to be not visible.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Menu item is not visible in dashboard menu.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php index 49a3bf024cd37..b98ff0ccf33b8 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Fixture/GlobalSearch/Query.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Fixture/GlobalSearch/Query.php index 1eada6511678d..71a2e9da3c13a 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Fixture/GlobalSearch/Query.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Fixture/GlobalSearch/Query.php @@ -1,6 +1,6 @@ params['attribute_code'] . '" field'); } - $date = date(str_replace($delta, '', $data['pattern']), $timestamp); + if (isset($data['apply_timezone']) && $data['apply_timezone'] === true) { + $date = new \DateTime(); + $date->setTimestamp($timestamp); + $date->setTimezone(new \DateTimeZone($_ENV['magento_timezone'])); + $date = $date->format(str_replace($delta, '', $data['pattern'])); + $this->isTimezoneApplied = true; + } else { + $date = date(str_replace($delta, '', $data['pattern']), $timestamp); + $this->isTimezoneApplied = false; + } if (!$date) { $date = date('m/d/Y'); } @@ -44,4 +61,14 @@ public function __construct(array $params, $data = []) $this->data = $data; } } + + /** + * Verifies if timezone setting has been already applied. + * + * @return bool + */ + public function isTimezoneApplied() + { + return $this->isTimezoneApplied; + } } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Handler/Conditions.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Handler/Conditions.php index dfcb011cd4c69..17f7debaa9227 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Handler/Conditions.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Handler/Conditions.php @@ -1,6 +1,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteGroup.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteGroup.xml index b87002d9eba5f..c0d4db696017c 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteGroup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteWebsite.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteWebsite.xml index 440f010e848fb..196f0bfd68237 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteWebsite.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/DeleteWebsite.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditGroup.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditGroup.xml index 1c22182af990d..378884bc00d84 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditGroup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditStore.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditStore.xml index 19ccb9cdcc703..5ca3e7ad68bf7 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditStore.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditStore.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditWebsite.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditWebsite.xml index e3279353dea6d..aea2587ee8444 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditWebsite.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/EditWebsite.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewGroupIndex.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewGroupIndex.xml index 1a742b0f8bf33..333f53c41bb0d 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewGroupIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewGroupIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewWebsiteIndex.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewWebsiteIndex.xml index ee5015ef30708..f5620d333f07e 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewWebsiteIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/NewWebsiteIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreDelete.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreDelete.xml index f5581e1e40d59..bef88d37f1a38 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreDelete.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreDelete.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreIndex.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreIndex.xml index 92db8dc5088f9..9cf5f24f1a7fc 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreNew.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreNew.xml index f1d30a39018e1..05a3091ed5ddc 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreNew.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/StoreNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfig.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfig.xml index 4f0dc30ff0230..3c4500e5cec92 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfig.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfig.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEdit.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEdit.xml index d7d5799fbb9d5..f6d5acd21b521 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEdit.xml @@ -1,7 +1,7 @@ @@ -11,5 +11,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml index 24c2ce030f7f0..269dfa18f0947 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml index a341341cf7c1d..c3f6419b24bd0 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Repository/ConfigData.xml @@ -1,11 +1,12 @@ - + @@ -150,7 +151,48 @@ + + + default + 0 + Yes + 1 + + + + + default + 0 + Yes + 1 + 1 + + + default + 0 + Yes + 1 + 1 + + + + + + default + 0 + No + 0 + + + default + 0 + No + 0 + + + + default 0 @@ -163,7 +205,43 @@ Yes 1 + + default + 0 + {{basic_url_to_secure}} + + + default + 0 + {{basic_url_to_secure}} + + + + + default + 0 + No + 0 + + + default + 0 + No + 0 + + + default + 0 + {{basic_url_to_unsecure}} + + + default + 0 + {{basic_url_to_unsecure}} + + + default @@ -195,6 +273,21 @@ + + + default + 0 + No + 0 + + + default + 0 + No + 0 + + + default @@ -205,6 +298,7 @@ + default @@ -212,5 +306,43 @@ 1 + + + + default + 0 + Yes + 1 + + + + + + default + 0 + No + 0 + + + + + + default + 0 + + DE + ES + GB + + + + + + + default + 0 + + + diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigPageVisibilityTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigPageVisibilityTest.php new file mode 100644 index 0000000000000..419f11ec61bc7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigPageVisibilityTest.php @@ -0,0 +1,49 @@ +configurationAdminPage = $configurationAdminPage; + } + + /** + * Test execution. + * + * @return void + */ + public function test() + { + $this->configurationAdminPage->open(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigPageVisibilityTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigPageVisibilityTest.xml new file mode 100644 index 0000000000000..a33572901c9f2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigPageVisibilityTest.xml @@ -0,0 +1,16 @@ + + + + + + severity:S1 + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigureSecureUrlsTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigureSecureUrlsTest.php new file mode 100644 index 0000000000000..07493b605b2f3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigureSecureUrlsTest.php @@ -0,0 +1,160 @@ + Configuration" page. + * 3. Select needed scope. + * 4. Go to "General > Web > Base URLs (Secure)" section. + * 5. Specify Base URL with Secure protocol in the same format as a Secure Base URL. + * (i) Make sure that Secure Base URL ends with a "/". + * 6. Enable Secure URLs for Storefront if there is a need. + * 7. Enable Secure URLs for Admin if there is a need. + * 8. Save the Config & refresh invalidated caches (Configuration, Page Cache). + * 9. Deploy static view files. + * + * 10. If Secure URLs for Storefront were enabled: + * 1. Assert that https is used all over the Storefront. + * 2. Assert that static content is deployed validly (ex: JS functionality works on Storefront). + * 3. Assert that Customer is redirected to https if trying to access the page directly via http. + * 11. If secure URLs for Storefront were disabled: + * 1. Assert that http is used all over the Storefront. + * 2. Assert that static content is deployed validly (ex: JS functionality works on Storefront). + * + * 12. If secure URLs for Admin were enabled: + * 1. Assert that https is used all over the Admin panel. + * 2. Assert that static content is deployed validly (ex: JS functionality works in Admin panel). + * 3. Assert that Merchant is redirected to https if trying to access the page directly via http. + * 13. If secure URLs for Admin were disabled: + * 1. Assert that http is used all over the Admin panel. + * 2. Assert that static content is deployed validly (ex: JS functionality works in Admin panel). + * 3. Assert that Merchant is redirected to http if trying to access the page directly via https. + * + * Postconditions: + * 1. Turn the Secure URLs usage off (with further cache refreshing & static content deploying). + * + * @ZephyrId MAGETWO-35408 + */ +class ConfigureSecureUrlsTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * "Configuration" page in Admin panel. + * + * @var SystemConfigEdit + */ + protected $configurationAdminPage; + + /** + * Cache CLI. + * + * @var Cache + */ + protected $cache; + + /** + * Static content CLI. + * + * @var StaticContent + */ + protected $staticContent; + + /** + * Prepare data for further test execution. + * + * @param FixtureFactory $fixtureFactory + * @param SystemConfigEdit $configurationAdminPage + * @param Cache $cache + * @param StaticContent $staticContent + * @return void + */ + public function __inject( + FixtureFactory $fixtureFactory, + SystemConfigEdit $configurationAdminPage, + Cache $cache, + StaticContent $staticContent + ) { + $this->fixtureFactory = $fixtureFactory; + $this->configurationAdminPage = $configurationAdminPage; + $this->cache = $cache; + $this->staticContent = $staticContent; + } + + /** + * Test execution. + * + * @param string $configData + * @return void + */ + public function test($configData) + { + $this->markTestSkipped( + 'MAGETWO-63197: ConfigureSecureUrlsTest is failing and next functional tests are also failing after it' + ); + $data = [ + 'web/secure/base_url' => [ + 'scope' => 'default', + 'scope_id' => 0, + 'value' => str_replace(['http', 'index.php/'], ['https', ''], $_ENV['app_frontend_url']) + ] + ]; + $config = $this->fixtureFactory->createByCode('configData', ['dataset' => $configData, 'data' => $data]); + $config->persist(); + + // Workaround until MTA-3879 is delivered. + $this->configurationAdminPage->open(); + $this->configurationAdminPage->getForm() + ->getGroup('web', 'secure') + ->setValue('web', 'secure', 'use_in_adminhtml', 'Yes'); + $this->configurationAdminPage->getPageActions()->save(); + $_ENV['app_backend_url'] = str_replace('http', 'https', $_ENV['app_backend_url']); + + $this->cache->flush(['config', 'full_page']); + $this->staticContent->deploy(); + } + + /** + * Revert all applied high-level changes. + * + * @return void + */ + public function tearDown() + { + $this->configurationAdminPage->open(); + $this->configurationAdminPage->getForm() + ->getGroup('web', 'secure') + ->setValue('web', 'secure', 'use_in_adminhtml', 'No'); + $this->configurationAdminPage->getPageActions()->save(); + $this->cache->flush(['config', 'full_page']); + $this->staticContent->deploy(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigureSecureUrlsTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigureSecureUrlsTest.xml new file mode 100644 index 0000000000000..d63e0639ea030 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ConfigureSecureUrlsTest.xml @@ -0,0 +1,17 @@ + + + + + + disable_https_frontend_admin + Marketing>Catalog Price Rule + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php index 048f92783b42d..2d35a36e4de20 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/ExpireAdminSessionTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.php index a75c3f94ccde7..003914baea0e4 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.php @@ -1,6 +1,6 @@ + stable:no search shows admin preview Some search term + stable:no search with 2 sign return no results :) + stable:no search product by sku orderInjectable::default::product::sku + stable:no search existed customer customer::johndoe_unique::lastname + stable:no search order (by order id) orderInjectable::default::id diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.php index 0c2cd138eb1c8..fc9081c72e0d3 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersDisableTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.php index 5dca7fad04e1f..7cb54a69a0607 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/HttpsHeadersEnableTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php index f75ea3ade05fc..4348e55772c5f 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestStep/OpenDashboardStep.php b/dev/tests/functional/tests/app/Magento/Backend/Test/TestStep/OpenDashboardStep.php new file mode 100644 index 0000000000000..30334a68cd83b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestStep/OpenDashboardStep.php @@ -0,0 +1,40 @@ +dashboard = $dashboard; + } + + /** + * Run step flow. + * + * @return void + */ + public function run() + { + $this->dashboard->open(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/etc/di.xml index bf3b7f2de9450..2803bf3d43746 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/etc/di.xml @@ -1,7 +1,7 @@ @@ -11,9 +11,29 @@ high + + + high + + + + + middle + + high + + + S1 + + + + + S1 + + diff --git a/dev/tests/functional/tests/app/Magento/Backup/Test/Block/Adminhtml/BackupGrid.php b/dev/tests/functional/tests/app/Magento/Backup/Test/Block/Adminhtml/BackupGrid.php index bf30b799b1120..bc54249310491 100644 --- a/dev/tests/functional/tests/app/Magento/Backup/Test/Block/Adminhtml/BackupGrid.php +++ b/dev/tests/functional/tests/app/Magento/Backup/Test/Block/Adminhtml/BackupGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml index 6b1e518034fc4..d2e96b900f205 100644 --- a/dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Backup/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Adminhtml/Report/Grid.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Adminhtml/Report/Grid.php index 0a82cece52eed..d6b888c990adc 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Adminhtml/Report/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Adminhtml/Report/Grid.php @@ -1,6 +1,6 @@ "//*[@id='braintree-hosted-field-number']", + "cc_exp_month" => "//*[@id='braintree-hosted-field-expirationMonth']", + "cc_exp_year" => "//*[@id='braintree-hosted-field-expirationYear']", + "cc_cid" => "//*[@id='braintree-hosted-field-cvv']", + ]; + + /** + * Error container selector. + * + * @var string + */ + protected $errorSelector = "/../../div[@class='hosted-error']"; + + /** + * Fill Braintree credit card form. + * + * @param FixtureInterface $fixture + * @param SimpleElement|null $element + * @return void + */ + public function fill(FixtureInterface $fixture, SimpleElement $element = null) + { + $this->braintreeForm = array_intersect_key($this->braintreeForm, $fixture->getData()); + $mapping = $this->dataMapping($fixture->getData()); + foreach ($this->braintreeForm as $field => $iframe) { + $element = $this->browser->find('body'); + $this->browser->waitUntil( + function () use ($element, $iframe) { + $fieldElement = $element->find($iframe, Locator::SELECTOR_XPATH); + return $fieldElement->isVisible() ? true : null; + } + ); + $iframeLocator = ObjectManager::getInstance()->create( + Locator::class, + [ + 'value' => $iframe, + 'strategy' => Locator::SELECTOR_XPATH + ] + ); + $this->browser->switchToFrame($iframeLocator); + $element = $this->browser->find('body'); + $this->browser->waitUntil( + function () use ($element) { + $fieldElement = $element->find('input'); + return $fieldElement->isVisible() ? true : null; + } + ); + $this->_fill([$mapping[$field]], $element); + $this->browser->switchToFrame(); + } + } + + /** + * Returns visible error messages. + * + * @param array $messages + * @return array + */ + public function getVisibleMessages(array $messages) + { + $textMessages = []; + foreach (array_keys($messages) as $field) { + $selector = $this->braintreeForm[$field] . $this->errorSelector; + $errorElement = $this->_rootElement->find($selector, Locator::SELECTOR_XPATH); + $textMessages[$field] = $errorElement->isVisible() ? $errorElement->getText() : null; + } + + return $textMessages; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.xml similarity index 53% rename from dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.xml rename to dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.xml index 6ea1ba9ee6e15..922eed35e23a4 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/BraintreeCc.xml @@ -1,23 +1,23 @@ - + #credit-card-number - - + + #expiration-month - - + + #expiration-year - - + + #cvv - + - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.php deleted file mode 100644 index 2179efc0d5bf1..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Cc.php +++ /dev/null @@ -1,55 +0,0 @@ - "#braintree-hosted-field-number", - "credit_card_exp_month" => "#braintree-hosted-field-expirationMonth", - "credit_card_exp_year" => "#braintree-hosted-field-expirationYear", - "cvv" => "#braintree-hosted-field-cvv", - ]; - - public function fill(FixtureInterface $fixture, SimpleElement $element = null) - { - $mapping = $this->dataMapping($fixture->getData()); - foreach ($this->braintreeForm as $field => $iframe) { - $element = $this->browser->find('body'); - $this->browser->waitUntil( - function () use ($element, $iframe) { - $fieldElement = $element->find($iframe); - return $fieldElement->isVisible() ? true : null; - } - ); - $this->browser->switchToFrame(new Locator($iframe)); - $element = $this->browser->find('body'); - $this->browser->waitUntil( - function () use ($element) { - $fieldElement = $element->find('input'); - return $fieldElement->isVisible() ? true : null; - } - ); - $this->_fill([$mapping[$field]], $element); - $this->browser->switchToFrame(); - } - } -} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Secure3d.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Secure3d.php index 145a8201e8800..5e405720f183b 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Secure3d.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Form/Secure3d.php @@ -1,6 +1,6 @@ @@ -11,4 +11,4 @@ input[name="external.field.password"] - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Info.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Info.php deleted file mode 100644 index 32dfb8f40fe87..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Info.php +++ /dev/null @@ -1,38 +0,0 @@ -_rootElement->getElements($this->info, Locator::SELECTOR_XPATH); - foreach ($elements as $row) { - $key = rtrim($row->find('./th', Locator::SELECTOR_XPATH)->getText(), ':'); - $value = $row->find('./td', Locator::SELECTOR_XPATH)->getText(); - $result[$key] = $value; - } - return $result; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Paypal/PopupWindow.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Paypal/PopupWindow.php index bef2dc8cdba7f..a4f8983d8538f 100755 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Paypal/PopupWindow.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Block/Paypal/PopupWindow.php @@ -1,6 +1,6 @@ "#payment_us_braintree_section_braintree_active", 'Enable PayPal through Braintree' => '#payment_us_braintree_section_braintree_active_braintree_paypal', - 'Vault enabled' => '#payment_us_braintree_section_braintree_braintree_cc_vault_active' + 'Vault Enabled' => '#payment_us_braintree_section_braintree_braintree_cc_vault_active' ]; /** diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php index bb1e067023157..e04a880cdcc41 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php @@ -1,18 +1,21 @@ getBraintreeInfoBlock()->getPaymentInfo(); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $actualPaymentInformation = $infoTab->getPaymentInfoBlock()->getData(); foreach ($paymentInformation as $key => $value) { \PHPUnit_Framework_Assert::assertArrayHasKey( $key, diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertCreditCardJsValidationMessagesArePresent.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertCreditCardJsValidationMessagesArePresent.php new file mode 100644 index 0000000000000..9cef593210f78 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertCreditCardJsValidationMessagesArePresent.php @@ -0,0 +1,46 @@ +getBraintreeBlock()->getVisibleMessages($expectedErrorMessages); + + foreach (array_keys($errorMessages) as $field) { + \PHPUnit_Framework_Assert::assertEquals( + $expectedErrorMessages[$field], + $errorMessages[$field], + "Wrong js validation error message is displayed for field: $field." + ); + } + } + + /** + * Returns string representation of successful assertion + * + * @return string + */ + public function toString() + { + return 'Js validation error messages are correct for required fields.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertDeviceDataIsPresentInBraintreeRequest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertDeviceDataIsPresentInBraintreeRequest.php new file mode 100644 index 0000000000000..f26dc0a44156a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertDeviceDataIsPresentInBraintreeRequest.php @@ -0,0 +1,52 @@ + \'{"device_session_id":"\w*","fraud_merchant_id":"\w*"}\'/'; + + /** + * Assert that device data is present in Braintree request. + * + * @param Log $log + * @return void + */ + public function processAssert(Log $log) + { + $file = $log->getFileContent(self::FILE_NAME); + \PHPUnit_Framework_Assert::assertRegExp( + self::DEVICE_DATA_PATTERN, + $file, + 'The device data is not present in Braintree request.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'The device data is present in Braintree request.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php index 96f84e4d3ef0f..2ae10ed4305ba 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php @@ -1,6 +1,6 @@ salesOrderView->getOrderHistoryBlock()->getCommentsHistory(); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $this->salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); $transactionId = null; - preg_match('/(\w+-*\w+)"/', $comments, $matches); + preg_match('/(\w+-*\w+)"/', $latestComment['comment'], $matches); if (!empty($matches[1])) { $transactionId = $matches[1]; } diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/CreditCardBraintree.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/BraintreeSandboxCustomer.xml similarity index 50% rename from dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/CreditCardBraintree.xml rename to dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/BraintreeSandboxCustomer.xml index e9baa301509ce..ed7d001af06d2 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/CreditCardBraintree.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/BraintreeSandboxCustomer.xml @@ -1,20 +1,19 @@ - - - - - + repository_class="Magento\Braintree\Test\Repository\BraintreeSandboxCustomer" + class="Magento\Braintree\Test\Fixture\BraintreeSandboxCustomer"> + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/Secure3dBraintree.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/Secure3dBraintree.xml index 84dc96bddb218..e8e5492b9240d 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/Secure3dBraintree.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Fixture/Secure3dBraintree.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/BraintreeSettlementReport.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/BraintreeSettlementReport.xml index 20359c41bd55f..4f22e2735ebca 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/BraintreeSettlementReport.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/BraintreeSettlementReport.xml @@ -1,12 +1,12 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SalesOrderView.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SalesOrderView.xml deleted file mode 100644 index be96e88c35f81..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SalesOrderView.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml index 836525e05f78e..1c99dd93d0ef5 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CatalogProductView.xml index 24a9b6292db99..c7bae02d2348a 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CatalogProductView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutCart.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutCart.xml index 28aca1189f182..cdb89f6f44d22 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutCart.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutCart.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutOnepage.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutOnepage.xml index 198a3bdc5ee2a..339f2b64bd0bf 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutOnepage.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Page/CheckoutOnepage.xml @@ -1,13 +1,13 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/BraintreeSandboxCustomer.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/BraintreeSandboxCustomer.xml new file mode 100644 index 0000000000000..e11d49b867d1a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/BraintreeSandboxCustomer.xml @@ -0,0 +1,17 @@ + + + + + + BRAINTREEE_ENVIRONMENT + BRAINTREEE_MERCHANT_ID + BRAINTREE_PUBLIC_KEY + BRAINTREE_PRIVATE_KEY + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml index 7f01e4f46106c..191e2763cadfe 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -11,26 +11,26 @@ payment 1 - PAYMENT_BRAINTREE_MERCHANT_ID - PAYMENT_BRAINTREE_MERCHANT_ID + Merchant ID + %braintree_disabled_fraud_merchant_id% payment 1 - PAYMENT_PAYMENT_BRAINTREE_PUBLIC_KEY - PAYMENT_PAYMENT_BRAINTREE_PUBLIC_KEY + Public Key + %braintree_disabled_fraud_public_key% payment 1 - PAYMENT_BRAINTREE_PRIVATE_KEY - PAYMENT_BRAINTREE_PRIVATE_KEY + Private Key + %braintree_disabled_fraud_private_key% payment 1 - PAYMENT_BRAINTREE_MERCHANT_ACCOUNT_ID - PAYMENT_BRAINTREE_MERCHANT_ACCOUNT_ID + Merchant Account ID + %braintree_disabled_fraud_merchant_account_id% payment @@ -51,6 +51,7 @@ 1 + payment @@ -59,6 +60,16 @@ 0 + + + + payment + 1 + Merchant Account ID + incorrect + + + payment @@ -67,6 +78,7 @@ authorize_capture + payment @@ -75,6 +87,7 @@ 1 + payment @@ -83,6 +96,7 @@ 0 + payment @@ -107,6 +121,7 @@ + payment @@ -121,6 +136,7 @@ 0 + payment @@ -135,6 +151,7 @@ 300 + payment @@ -143,6 +160,7 @@ 0 + payment @@ -151,6 +169,7 @@ 1 + payment @@ -159,6 +178,7 @@ 0 + payment @@ -173,6 +193,7 @@ authorize + payment @@ -181,7 +202,14 @@ 0 + + + payment + 1 + Yes + 1 + payment 1 @@ -189,6 +217,16 @@ authorize_capture + + + + payment + 1 + No + 0 + + + payment @@ -197,6 +235,7 @@ 1 + payment @@ -205,6 +244,7 @@ 0 + payment @@ -213,6 +253,7 @@ 1 + payment @@ -221,6 +262,7 @@ 0 + payment @@ -229,6 +271,7 @@ 1 + payment @@ -237,5 +280,146 @@ 0 + + + + payment + 1 + Merchant ID + %braintree_enabled_fraud_merchant_id% + + + payment + 1 + Public Key + %braintree_enabled_fraud_public_key% + + + payment + 1 + Private Key + %braintree_enabled_fraud_private_key% + + + payment + 1 + Merchant Account ID + %braintree_enabled_fraud_merchant_account_id% + + + payment + 1 + Authorize + authorize + + + payment + 1 + Yes + 1 + + + payment + 1 + Yes + 1 + + + + + + payment + 1 + No + 0 + + + + + + payment + 1 + No + 0 + + + + + + payment + 1 + Yes + 1 + + + + + + payment + 1 + + AE + VI + + + + + + + payment + 1 + + CUP + AE + VI + MC + DI + JCB + DN + MI + + + + + + + payment + 1 + Specific Countries + 1 + + + payment + 1 + + GB + + + + + + + payment + 1 + All Allowed Countries + 0 + + + + + + payment + 1 + {"GB":["VI"],"US":["MC"]} + + + + + + payment + 1 + [] + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml index e750aa9cb4234..6e202e4bc178b 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/CreditCard.xml @@ -1,29 +1,41 @@ - - - 4111111111111111 - 01 - 2020 - 123 - + - 4000000000000002 - 01 - 20 - 123 + braintree + 4000000000000002 + 01 + 20 + 123 + - 4000000000000028 - 01 - 2020 - 123 + braintree + 4000000000000028 + 01 + 2020 + 123 + + + + braintree + 4000111111111511 + 01 + 2020 + 123 + + + + braintree + 4111111111111111 + 01 - January + 2020 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/Secure3d.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/Secure3d.xml index 14cec3498b936..54b07c22892d2 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/Secure3d.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/Secure3d.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.php index 6601bd44892c9..d49bc07f8f8f7 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/BraintreeSettlementReportTest.php @@ -1,6 +1,6 @@ @@ -18,11 +18,11 @@ 15.00 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing - test_type:extended_acceptance_test, test_type:3rd_party_test + test_type:extended_acceptance_test, test_type:3rd_party_test, severity:S1 @@ -30,4 +30,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalCartTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalCartTest.php index a0bf482705f55..b0a309dc96c18 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalCartTest.php @@ -1,6 +1,6 @@ @@ -20,7 +20,7 @@ braintree_paypal braintree, braintree_paypal, braintree_paypal_skip_order_review Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 @@ -42,7 +42,7 @@ braintree_paypal braintree, braintree_paypal, braintree_paypal_sale, braintree_paypal_skip_order_review Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.php index f0f0291b33e20..4c5ccbc8f684f 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.php @@ -1,6 +1,6 @@ @@ -20,7 +20,7 @@ braintree_paypal braintree, braintree_paypal, braintree_paypal_skip_order_review Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 @@ -42,7 +42,7 @@ braintree_paypal braintree, braintree_paypal, braintree_paypal_sale, braintree_paypal_skip_order_review Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.php index 6554845d5ff81..0570c903f863b 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreePaypalTest.php @@ -1,6 +1,6 @@ @@ -11,10 +11,17 @@ catalogProductSimple::product_10_dollar bundleProduct::bundle_fixed_100_dollar_product default - login + guest us_ca_ny_rule - - 139.9 + + + 0 + + + + + 139.90 + US_address_1_without_email Flat Rate @@ -22,9 +29,7 @@ braintree_paypal braintree, braintree_paypal, braintree_paypal_sale, braintree_paypal_skip_order_review sale - Back, Send Email, Credit Memo, Hold, Ship, Reorder - - - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 @@ -32,22 +37,36 @@ catalogProductSimple::simple_for_sales default - login + guest us_ca_ny_rule - - 621.2 + + + 0 + + + 1 + + + + + 0 + + + + + 621.20 + + + 606.20 + US_address_1_without_email Flat Rate Fixed braintree_paypal braintree, braintree_paypal, braintree_paypal_skip_order_review - Back, Send Email, Credit Memo, Hold, Ship, Reorder 2 - 1 - default - Yes - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreeTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreeTest.php new file mode 100644 index 0000000000000..16aa003bd04b7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreeTest.php @@ -0,0 +1,40 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreeTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreeTest.xml new file mode 100644 index 0000000000000..638c76cadb55d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineCreditMemoBraintreeTest.xml @@ -0,0 +1,102 @@ + + + + + + test_type:3rd_party_test, severity:S1 + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + + default + braintree_sandbox_default + us_ca_ny_rule + US_address_1_without_email + guest + + Flat Rate + Fixed + + braintree + visa_default + braintree + braintree + Closed + + + 0 + + + + + 145.98 + + + + Refund + Yes + + + + + + + + test_type:3rd_party_test, severity:S1 + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + + default + braintree_sandbox_default + us_ca_ny_rule + US_address_1_without_email + guest + + Flat Rate + Fixed + + braintree + visa_default + braintree + braintree + Processing + + + 0 + + + 0 + + + + + 0 + + + + + 134.07 + + + 1.08 + + + + + 0 + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml index 702a732e937ea..9486335cf4e43 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOnlineInvoiceEntityTest.xml @@ -1,7 +1,7 @@ @@ -18,18 +18,18 @@ Flat Rate Fixed - 139.9 + 139.90 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing Back, Send Email, Credit Memo, Hold, Ship, Reorder - No comments - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 @@ -50,15 +50,15 @@ 118.25 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing Back, Send Email, Credit Memo, Hold, Ship, Reorder 1 No comments - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml index 80596fb577b97..7f12005da8067 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderBackendTest.xml @@ -1,14 +1,14 @@ - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 catalogProductSimple::product_10_dollar configurableProduct::with_one_option bundleProduct::bundle_fixed_100_dollar_product @@ -22,8 +22,8 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree Processing Back, Cancel, Send Email, Hold, Invoice, Ship, Reorder, Edit @@ -32,11 +32,10 @@ - - test_type:extended_acceptance_test, test_type:3rd_party_test + test_type:extended_acceptance_test, test_type:3rd_party_test, severity:S0 catalogProductSimple::product_10_dollar configurableProduct::with_one_option bundleProduct::bundle_fixed_100_dollar_product @@ -53,8 +52,8 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree, braintree_sale Processing Back, Send Email, Hold, Ship, Reorder @@ -63,7 +62,28 @@ - + + + + test_type:3rd_party_test, severity:S0 + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + default + us_ca_ny_rule + US_address_1_without_email + No + Flat Rate + Fixed + + 145.98 + + braintree + visa_braintree_fraud_rejected + braintree + Processing + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.php new file mode 100644 index 0000000000000..721c09867a58a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.php @@ -0,0 +1,56 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.xml new file mode 100644 index 0000000000000..b6b10c7e7bfe4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateOrderWithPayPalBraintreeVaultBackendTest.xml @@ -0,0 +1,32 @@ + + + + + + test_type:3rd_party_test, severity:S0 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + login + Flat Rate + Fixed + braintree_paypal + braintree_paypal_vault + Processing + braintree, braintree_paypal, braintree_paypal_use_vault, braintree_paypal_skip_order_review + + 15.00 + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml index 4f05723609c2a..b1ef5a0c4e39c 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CreateVaultOrderBackendTest.xml @@ -1,14 +1,14 @@ - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 catalogProductSimple::product_10_dollar default US_address_1_without_email @@ -19,8 +19,9 @@ 15.00 braintree - credit_card_braintree - visa_braintree + braintree_cc_vault + visa_default + braintree Yes braintree, braintree_use_vault Processing diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePayPalBraintreeTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePayPalBraintreeTest.php index 7048984886582..64b6cd7d7eb06 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePayPalBraintreeTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/InvoicePayPalBraintreeTest.php @@ -1,6 +1,6 @@ @@ -15,10 +15,10 @@ Flat Rate Fixed - 139.9 + 139.90 - 139.9 + 139.90 braintree_paypal braintree, braintree_paypal, braintree_paypal_skip_order_review @@ -26,12 +26,12 @@ - No comments - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 - + Partial capture for order placed within Braintree PayPal catalogProductSimple::product_100_dollar us_illinois_tax_rule @@ -43,7 +43,6 @@ 118.25 - 108.25 braintree_paypal braintree, braintree_paypal, braintree_paypal_skip_order_review @@ -51,10 +50,18 @@ 1 No comments - test_type:3rd_party_test + Processing + + Capture + No + + test_type:3rd_party_test, severity:S0 - + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.php index 41f637d52941d..ab3941c1723f0 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.php @@ -1,6 +1,6 @@ Orders page. + * 3. Open the placed order. + * 4. Click Accept button. + * 5. Perform assertions. + * + * @group Braintree + * @ZephyrId MAGETWO-56023 */ class OnePageCheckoutAcceptPaymentTest extends Scenario { /* tags */ const MVP = 'yes'; const TEST_TYPE = 'acceptance_test, 3rd_party_test'; + const SEVERITY = 'S2'; /* end tags */ /** diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml index f42054b4a0732..f1fdbbde80ede 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutAcceptPaymentTest.xml @@ -1,7 +1,7 @@ @@ -17,11 +17,11 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree,braintree_fraudprotection Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S2 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml new file mode 100644 index 0000000000000..3806a29c695db --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDeclinedTest.xml @@ -0,0 +1,71 @@ + + + + + + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + login + Flat Rate + Fixed + braintree + visa_braintree_fraud_rejected + Transaction has been declined. Please try again later. + braintree_fraud_tool_enabled_account, braintree_fraudprotection + Processing + test_type:3rd_party_test, severity:S1 + + + + catalogProductSimple::product_10_dollar + default + US_address_1 + guest + Flat Rate + Fixed + braintree + visa_default + braintree + Sorry, but something went wrong + braintree, braintree_incorrect_merchant_account_id + Processing + test_type:3rd_party_test, severity:S1 + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + braintree + braintree + mastercard_default + Please, enter valid Credit Card Number + braintree, braintree_cctypes_AE_VI + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + customer_UK_1_default_billing_address + login + Flat Rate + Fixed + braintree + braintree + mastercard_default + Please, enter valid Credit Card Number + braintree, braintree_countrycreditcard_US_MS_GB_VI + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.php index 69fd4a8323eca..519270bb30d0e 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.php @@ -1,6 +1,6 @@ Orders page. + * 3. Open the placed order. + * 4. Click Deny button. + * 5. Perform assertions. + * + * @group Braintree + * @ZephyrId MAGETWO-56024 */ class OnePageCheckoutDenyPaymentTest extends Scenario { /* tags */ const MVP = 'yes'; const TEST_TYPE = 'acceptance_test, 3rd_party_test'; + const SEVERITY = 'S2'; /* end tags */ /** diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml index 45476abfdfd12..172bd7511547e 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutDenyPaymentTest.xml @@ -1,7 +1,7 @@ @@ -17,11 +17,11 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + visa_default + braintree braintree,braintree_fraudprotection Canceled - test_type:3rd_party_test + test_type:3rd_party_test, severity:S2 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutFromMiniShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutFromMiniShoppingCartTest.xml new file mode 100644 index 0000000000000..34a38554c6302 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutFromMiniShoppingCartTest.xml @@ -0,0 +1,62 @@ + + + + + + catalogProductVirtual::product_50_dollar + johndoe_with_addresses + login + braintree + visa_braintree_no_cvv + braintree, braintree_paypal_skip_order_review, braintree_cvv_disabled + test_type:3rd_party_test, severity:S1 + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + braintree + visa_default + braintree + braintree, braintree_cctypes_AE_VI + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + UK_address_without_email + guest + Flat Rate + Fixed + braintree + visa_default + braintree + braintree, braintree_specific_country_GB + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + customer_UK_1_default_billing_address + login + Flat Rate + Fixed + braintree + visa_default + braintree + braintree, braintree_countrycreditcard_US_MS_GB_VI + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml index a1ceaa53da045..b0971945fc85b 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutTest.xml @@ -1,7 +1,7 @@ @@ -21,11 +21,11 @@ 145.98 braintree - credit_card_braintree visa_braintree_3dsecure + false braintree, braintree_3d_secure_not_triggered_due_threshold Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 @@ -44,11 +44,11 @@ 145.98 braintree - credit_card_braintree visa_braintree_3dsecure + false braintree, braintree_3d_secure_uk Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 @@ -67,17 +67,18 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree + false braintree Processing - test_type:extended_acceptance_test, test_type:3rd_party_test + test_type:extended_acceptance_test, test_type:3rd_party_test, severity:S0 - + catalogProductSimple::product_10_dollar configurableProduct::with_one_option bundleProduct::bundle_fixed_100_dollar_product @@ -94,15 +95,31 @@ 145.98 braintree - credit_card_braintree - visa_braintree + visa_default + braintree + false braintree, braintree_sale Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + login + Flat Rate + Fixed + braintree + visa_default + braintree + braintree_fraud_tool_enabled_account, braintree_fraudprotection + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.php new file mode 100644 index 0000000000000..6fe3663f9a5f4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.php @@ -0,0 +1,49 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml new file mode 100644 index 0000000000000..8b91a3dc18de4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureFailedTest.xml @@ -0,0 +1,27 @@ + + + + + + catalogProductSimple::product_10_dollar + default + US_address_1 + guest + Flat Rate + Fixed + braintree + visa_braintree_3dsecure_failed + secure3d_braintree + braintree, braintree_3d_secure + Please try again with another form of payment. + Processing + test_type:3rd_party_test, severity:S1 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.php index 32599aa090651..134a7bde1c490 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWith3dSecureTest.php @@ -1,6 +1,6 @@ @@ -22,7 +22,6 @@ 145.98 braintree - credit_card_braintree visa_braintree_3dsecure 1 @@ -31,7 +30,7 @@ secure3d_braintree braintree, braintree_3d_secure Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithBraintreePaypalTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithBraintreePaypalTest.php index 9cf0e9c90c121..a78ca71ea31f0 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithBraintreePaypalTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithBraintreePaypalTest.php @@ -1,6 +1,6 @@ @@ -21,7 +21,7 @@ braintree_paypal braintree, braintree_paypal, braintree_paypal_skip_order_review Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 @@ -44,11 +44,27 @@ braintree_paypal braintree, braintree_paypal, braintree_paypal_sale, braintree_paypal_skip_order_review Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 + + catalogProductVirtual::product_50_dollar + default + guest + + 50.00 + + braintree_paypal + braintree, braintree_paypal, braintree_paypal_skip_order_review + Processing + test_type:3rd_party_test, severity:S2 + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml index 89d67936ab0c6..2fc94557fd2c5 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/OnePageCheckoutWithDiscountTest.xml @@ -1,7 +1,7 @@ @@ -17,20 +17,38 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + visa_default + braintree 10.00 Yes braintree, braintree_use_vault Processing - test_type:3rd_party_test - Back, Cancel, Send Email, Hold, Invoice, Ship, Reorder, Edit + test_type:3rd_party_test, severity:S1 + + + + + + Use saved for Braintree credit card on checkout + catalogProductSimple::product_10_dollar + default + active_sales_rule_with_fixed_price_discount_coupon + US_address_1_without_email + login + Free Shipping + Free + free + + 0.00 + + braintree, braintree_use_vault, freeshipping + Pending + test_type:3rd_party_test, severity:S1 - diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml index 88ab2ef65c9a0..6199ede716caa 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/ReorderUsingVaultTest.xml @@ -1,13 +1,13 @@ - + Reorder from Admin with saved within Braintree credit card for Guest Customer catalogProductSimple::product_10_dollar default @@ -19,11 +19,13 @@ 15.00 braintree - credit_card_braintree - visa_braintree + braintree_cc_vault + false + visa_default + braintree braintree, braintree_use_vault Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/SaveUseDeleteVaultForPaypalBraintreeTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/SaveUseDeleteVaultForPaypalBraintreeTest.php index f6813b74e40d7..dd7a6aec96cc2 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/SaveUseDeleteVaultForPaypalBraintreeTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/SaveUseDeleteVaultForPaypalBraintreeTest.php @@ -1,6 +1,6 @@ @@ -19,10 +19,11 @@ 15.00 braintree_paypal + braintree_paypal_vault Yes braintree, braintree_paypal, braintree_paypal_use_vault Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml index 4b061fb2664b8..789f3885f281e 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultOnCheckoutTest.xml @@ -1,7 +1,7 @@ @@ -16,12 +16,13 @@ Flat Rate Fixed braintree - credit_card_braintree - visa_braintree + braintree_cc_vault + visa_default + braintree Yes braintree, braintree_use_vault Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 Back, Cancel, Send Email, Hold, Invoice, Ship, Reorder, Edit diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.php index 13b8240d4c49e..0e319189443d3 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/UseVaultWith3dSecureOnCheckoutTest.php @@ -1,6 +1,6 @@ @@ -16,7 +16,7 @@ Flat Rate Fixed braintree - credit_card_braintree + braintree_cc_vault visa_braintree_3dsecure 1 @@ -26,7 +26,7 @@ Yes braintree, braintree_use_vault, braintree_3d_secure Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 Back, Cancel, Send Email, Hold, Invoice, Ship diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/VerifyPaymentMethodOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/VerifyPaymentMethodOnCheckoutTest.xml new file mode 100644 index 0000000000000..30f749df99f55 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/VerifyPaymentMethodOnCheckoutTest.xml @@ -0,0 +1,23 @@ + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + braintree + braintree, braintree_specific_country_GB + + + + diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/AcceptPaymentStep.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/AcceptPaymentStep.php index 6565652f604cb..9da200a2eee8f 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/AcceptPaymentStep.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/AcceptPaymentStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; + $this->secure3d = $secure3d; + } + + /** + * Click 'Place order' button and submit 3D secure verification. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + + $this->checkoutOnepage->getBraintree3dSecureBlock()->fill($this->secure3d); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/PlaceOrderWith3dSecureStep.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/PlaceOrderWith3dSecureStep.php index 1e9855a0f1fea..e44e6390337ff 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/PlaceOrderWith3dSecureStep.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/PlaceOrderWith3dSecureStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; $this->assertGrandTotalOrderReview = $assertGrandTotalOrderReview; + $this->assertBillingAddressAbsentInPayment = $assertBillingAddressAbsentInPayment; $this->checkoutOnepageSuccess = $checkoutOnepageSuccess; $this->fixtureFactory = $fixtureFactory; $this->products = $products; $this->prices = $prices; + $this->order = $order; } /** - * @inheritdoc + * Place order after checking order totals on review step. + * + * @return array */ public function run() { if (isset($this->prices['grandTotal'])) { $this->assertGrandTotalOrderReview->processAssert($this->checkoutOnepage, $this->prices['grandTotal']); } + + $this->assertBillingAddressAbsentInPayment->processAssert($this->checkoutOnepage); + $parentWindow = $this->checkoutOnepage->getPaymentBlock() ->getSelectedPaymentMethodBlock() ->clickPayWithPaypal(); $this->checkoutOnepage->getBraintreePaypalBlock()->process($parentWindow); - + $data = [ + 'entity_id' => ['products' => $this->products] + ]; + $orderData = $this->order !== null ? $this->order->getData() : []; $order = $this->fixtureFactory->createByCode( 'orderInjectable', - [ - 'data' => [ - 'entity_id' => ['products' => $this->products] - ] - ] + ['data' => array_merge($data, $orderData)] ); + return [ 'orderId' => $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(), 'order' => $order diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/SettleTransactionStep.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/SettleTransactionStep.php new file mode 100644 index 0000000000000..977b95fb8b9aa --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestStep/SettleTransactionStep.php @@ -0,0 +1,93 @@ +braintreeSandboxCustomer = $braintreeSandboxCustomer; + $this->salesOrder = $salesOrder; + $this->salesOrderView = $salesOrderView; + $this->orderId = $orderId; + } + + /** + * Settle transaction for Braintree Credit Card. + * + * @return void + */ + public function run() + { + $credentials = $this->braintreeSandboxCustomer->getData(); + $gateway = ObjectManagerFactory::getObjectManager()->create(Gateway::class, ['config' => $credentials]); + $transactionId = $this->getTransactionId(); + $gateway->testing()->settle($transactionId); + } + + /** + * Get transaction id. + * + * @return string + */ + private function getTransactionId() + { + $this->salesOrder->open(); + $this->salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $this->orderId]); + $this->salesOrderView->getOrderForm()->openTab('transactions'); + $actualTransactions = $this->salesOrderView->getOrderForm()->getTab('transactions')->getGridBlock()->getIds(); + + return current(array_keys($actualTransactions)); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/di.xml index be2d771e47f5b..2e3b2b1d025db 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/di.xml @@ -1,19 +1,29 @@ - high + S1 - high + S1 + + + + + S1 + + + + + S1 diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml index 34f4be6493838..ffe67f1979ee0 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/etc/testcase.xml @@ -1,7 +1,7 @@ @@ -21,6 +21,19 @@ + + + + + + + + + + + + + @@ -106,8 +119,8 @@ - - + + @@ -158,4 +171,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php index e94ec38d010f3..47b4459abea0b 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle.php @@ -1,6 +1,6 @@ _rootElement->find($this->bundleOptions, Locator::SELECTOR_XPATH); + + if (isset($fields['bundle_selections']['value']['bundle_options'])) { + foreach ($fields['bundle_selections']['value']['bundle_options'] as $key => $bundleOption) { + $count = $key + 1; + $itemOption = $context->find(sprintf($this->openOption, $count), Locator::SELECTOR_XPATH); + $isContent = $context->find(sprintf($this->optionContent, $count), Locator::SELECTOR_XPATH) + ->isVisible(); + if ($itemOption->isVisible() && !$isContent) { + $itemOption->click(); + } elseif (!$itemOption->isVisible()) { + $this->_rootElement->find($this->addNewOption)->click(); + } + $this->getBundleOptionBlock($count, $context)->fillOption($bundleOption); + } + } + + if (isset($fields['bundle_selections']['value']['bundle_options_delete'])) { + $this->deleteFieldsData($fields['bundle_selections']['value']['bundle_options_delete']); + } + + return $this; + } + + /** + * Delete some bundle options. + * + * @param array $fields + * @return $this + */ + public function deleteFieldsData(array $fields) + { $context = $this->_rootElement->find($this->bundleOptions, Locator::SELECTOR_XPATH); - foreach ($fields['bundle_selections']['value']['bundle_options'] as $key => $bundleOption) { - $count = $key + 1; - $itemOption = $context->find(sprintf($this->openOption, $count), Locator::SELECTOR_XPATH); - $isContent = $context->find(sprintf($this->optionContent, $count), Locator::SELECTOR_XPATH)->isVisible(); - if ($itemOption->isVisible() && !$isContent) { - $itemOption->click(); - } elseif (!$itemOption->isVisible()) { - $this->_rootElement->find($this->addNewOption)->click(); + foreach (array_keys($fields) as $key) { + $bundleOptionIndex = $key + 1; + $deleteOption = $context->find( + sprintf($this->deleteOption, $bundleOptionIndex), + Locator::SELECTOR_XPATH + ); + if ($deleteOption->isVisible()) { + $deleteOption->click(); } - $this->getBundleOptionBlock($count, $context)->fillOption($bundleOption); } return $this; } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option.php index a520c1a473c69..1f0974df3aeb7 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Search/Grid.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Search/Grid.php index 94e6fae9bebf2..18f0daa709e74 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Search/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Bundle/Option/Search/Grid.php @@ -1,6 +1,6 @@ @@ -21,6 +21,10 @@ [name$='[selection_qty]'] + + [name$='[selection_can_change_qty]'] + checkbox + span[data-index="name"] diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.php index 6859320af5d9d..c4ed84d37e384 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/Composite/Configure.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/ProductForm.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/ProductForm.xml index fa09470d5f450..a16db6f1dc896 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/ProductForm.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Adminhtml/Product/ProductForm.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php index db349d16a86c6..0a8050777f6fb 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View.php @@ -1,16 +1,15 @@ blockFactory->create( + Summary::class, + ['element' => $this->_rootElement->find($this->summaryBlockSelector)] + ); + } + /** * Click "Customize and add to cart button". * @@ -76,6 +95,7 @@ function () use ($browser, $selector) { ); $this->_rootElement->find($this->customizeButton)->click(); $this->waitForElementVisible($this->addToCart); + $this->waitForElementVisible($this->visibleOptions, Locator::SELECTOR_XPATH); } /** @@ -114,4 +134,19 @@ public function fillOptions(FixtureInterface $product) } $this->getBundleBlock()->fillBundleOptions($bundleCheckoutData); } + + /** + * Fill in the custom option data. + * + * @param array $optionsData + * @return void + */ + public function fillOptionsWithCustomData(array $optionsData = []) + { + if (!$this->getBundleBlock()->isVisible()) { + $this->clickCustomize(); + } + + $this->getBundleBlock()->fillBundleOptions($optionsData); + } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary.php new file mode 100644 index 0000000000000..5072d93e95327 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary.php @@ -0,0 +1,52 @@ +blockFactory->create( + ConfiguredPrice::class, + ['element' => $this->_rootElement->find($this->configuredPriceBlockSelector)] + ); + } + + /** + * Get Bundle Summary row items. + * + * @return \Magento\Mtf\Client\ElementInterface[] + */ + public function getSummaryItems() + { + return $this->_rootElement->getElements($this->summaryItemsSelector); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary/ConfiguredPrice.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary/ConfiguredPrice.php new file mode 100644 index 0000000000000..191f5e010dbc1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Summary/ConfiguredPrice.php @@ -0,0 +1,35 @@ + [ + 'selector' => '.price', + ] + ]; + + /** + * This method returns the price represented by the block. + * + * @param string $currency + * @return string|null + */ + public function getPrice($currency = '$') + { + return $this->getTypePrice('configured_price', $currency); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php index 23ac2d25ee017..74d21908957c9 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Bundle.php @@ -1,6 +1,6 @@ product = $product; $bundleSelections = $product->getBundleSelections(); $bundleOptions = isset($bundleSelections['bundle_options']) ? $bundleSelections['bundle_options'] : []; $listFormOptions = $this->getListOptions(); $formOptions = []; - foreach ($bundleOptions as $option) { + foreach ($bundleOptions as $index => $option) { $title = $option['title']; if (!isset($listFormOptions[$title])) { throw new \Exception("Can't find option: \"{$title}\""); } + $this->optionIndex = $index; /** @var SimpleElement $optionElement */ $optionElement = $listFormOptions[$title]; - $getTypeData = 'get' . $this->optionNameConvert($option['type']) . 'Data'; + $getTypeData = 'get' . $this->optionNameConvert($option['frontend_type']) . 'Data'; $optionData = $this->$getTypeData($optionElement); $optionData['title'] = $title; - $optionData['type'] = $option['type']; + $optionData['type'] = $option['frontend_type']; $optionData['is_require'] = $optionElement->find($this->required, Locator::SELECTOR_XPATH)->isVisible() ? 'Yes' : 'No'; $formOptions[] = $optionData; } - return $formOptions; } + /** + * Check if bundle option is visible. + * + * @param string $optionTitle + * @return bool + */ + public function isOptionVisible($optionTitle) + { + return isset($this->getListOptions()[$optionTitle]); + } + /** * Get list options * @@ -151,6 +191,9 @@ protected function getListOptions() */ protected function getDropdownData(SimpleElement $option) { + if ($this->isOneProductInStock($this->product)) { + return ['options' => $this->getFlatTextData()]; + } $select = $option->find($this->selectOption, Locator::SELECTOR_XPATH, 'select'); // Skip "Choose option ..."(option #1) return $this->getSelectOptionsData($select, 2); @@ -263,13 +306,16 @@ public function fillBundleOptions($bundleOptions) { foreach ($bundleOptions as $option) { $selector = sprintf($this->bundleOptionBlock, $option['title']); - /** @var Option $optionBlock */ - $optionBlock = $this->blockFactory->create( - 'Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option\\' - . $this->optionNameConvert($option['type']), - ['element' => $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)] - ); - $optionBlock->fillOption($option['value']); + $useDefault = isset($option['use_default']) && strtolower($option['use_default']) == 'true' ? true : false; + if (!$useDefault) { + /** @var Option $optionBlock */ + $optionBlock = $this->blockFactory->create( + 'Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option\\' + . $this->optionNameConvert($option['frontend_type']), + ['element' => $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)] + ); + $optionBlock->fillOption($option['value']); + } } } @@ -284,4 +330,43 @@ protected function optionNameConvert($optionType) $trimmedOptionType = preg_replace('/[^a-zA-Z]/', '', $optionType); return ucfirst(strtolower($trimmedOptionType)); } + + /** + * Check count products with 'In Stock' status. + * + * @param BundleProduct $products + * @return bool + */ + private function isOneProductInStock(BundleProduct $products) + { + $result = []; + $products = $products->getBundleSelections()['products'][$this->optionIndex]; + foreach ($products as $product) { + $status = $product->getData()['quantity_and_stock_status']['is_in_stock']; + if ($status == 'In Stock') { + $result[] = $product; + } + } + if (count($result) == 1) { + return true; + } + return false; + } + + /** + * Return list options. + * + * @return array + */ + private function getFlatTextData() + { + $productPrice = $this->_rootElement->find($this->assignedProductPrice)->getText(); + $productPrice = preg_replace("/[^0-9.,]/", '', $productPrice); + $productName = $this->_rootElement->find($this->assignedProductName)->getText(); + $options[$productName] = [ + 'title' => $productName, + 'price' => number_format($productPrice, 2) + ]; + return $options; + } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option.php index be6f7235acc24..29202effef06a 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option.php @@ -3,7 +3,7 @@ * @category Mtf * @package Mtf * @subpackage functional_tests - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Checkbox.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Checkbox.php index 8d0a28cc75b4b..a6a3b8ffc5053 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Checkbox.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Checkbox.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Dropdown.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Dropdown.php index 4190177b70fca..bc870760c8757 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Dropdown.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Dropdown.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Element/Qty.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Element/Qty.php new file mode 100644 index 0000000000000..72bd74c441b5d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Element/Qty.php @@ -0,0 +1,37 @@ +keys([self::RIGHT, self::BACKSPACE, $value]); + $this->context->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.php new file mode 100644 index 0000000000000..0a6238ffdf214 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Hidden.php @@ -0,0 +1,17 @@ + + + + + + input.qty + Magento\Bundle\Test\Block\Catalog\Product\View\Type\Option\Element\Qty + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Multiple.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Multiple.php index cbb23c9f165e6..73b5617a10995 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Multiple.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Multiple.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Radiobuttons.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Radiobuttons.php index 734188b78aea7..63cd929ebc65d 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Radiobuttons.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Block/Catalog/Product/View/Type/Option/Radiobuttons.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php index 3afb9dfba79f8..d7fc37acc7bf0 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php @@ -1,6 +1,6 @@ $bundleOption) { $optionData = [ 'title' => $bundleOption['title'], - 'type' => $bundleOption['type'], + 'type' => $bundleOption['frontend_type'], 'is_require' => $bundleOption['required'], ]; + $key = 0; foreach ($bundleOption['assigned_products'] as $productKey => $assignedProduct) { - $price = isset($assignedProduct['data']['selection_price_value']) - ? $assignedProduct['data']['selection_price_value'] - : $bundleSelections['products'][$optionKey][$productKey]->getPrice(); + if ($this->isInStock($product, $key++)) { + $price = isset($assignedProduct['data']['selection_price_value']) + ? $assignedProduct['data']['selection_price_value'] + : $bundleSelections['products'][$optionKey][$productKey]->getPrice(); - $optionData['options'][$productKey] = [ - 'title' => $assignedProduct['search_data']['name'], - 'price' => number_format($price, 2), - ]; + $optionData['options'][$productKey] = [ + 'title' => $assignedProduct['search_data']['name'], + 'price' => number_format($price, 2), + ]; + } } $result[$optionKey] = $optionData; @@ -82,6 +85,24 @@ protected function prepareBundleOptions(BundleProduct $product) return $result; } + /** + * Check product attribute 'is_in_stock'. + * + * @param BundleProduct $product + * @param int $key + * @return bool + */ + private function isInStock(BundleProduct $product, $key) + { + $assignedProducts = $product->getBundleSelections()['products'][0]; + $status = $assignedProducts[$key]->getData()['quantity_and_stock_status']['is_in_stock']; + + if ($status == 'In Stock') { + return true; + } + return false; + } + /** * Return Text if displayed on frontend equals with fixture. * diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsSummaryOnProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsSummaryOnProductPage.php new file mode 100644 index 0000000000000..93afcd6b1ebd3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsSummaryOnProductPage.php @@ -0,0 +1,102 @@ +open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $bundleOptions = $product->getData()['bundle_selections']['bundle_options']; + $bundleViewBlock = $catalogProductView->getBundleViewBlock(); + $configuredPriceBlock = $bundleViewBlock->getBundleSummaryBlock()->getConfiguredPriceBlock(); + foreach ($bundleOptions as $bundleOption) { + foreach ($bundleOption['assigned_products'] as $assignedProduct) { + $bundleViewBlock->fillOptionsWithCustomData([ + [ + 'title' => $bundleOption['title'], + 'type' => $bundleOption['type'], + 'frontend_type' => $bundleOption['type'], + 'value' => [ + 'name' => $assignedProduct['search_data']['name'] + ] + ] + ]); + $assignedProductPrice = (double)$assignedProduct['data']['selection_price_value']; + $assignedProductQty = (double)$assignedProduct['data']['selection_qty']; + + foreach ($bundleViewBlock->getBundleSummaryBlock()->getSummaryItems() as $bundleSummaryItem) { + $bundleSummaryItemText = $bundleSummaryItem->getText(); + if (strpos($bundleSummaryItemText, $assignedProduct['search_data']['name']) !== false) { + $optionData = $this->getBundleOptionData($bundleSummaryItemText); + $optionData['price'] = (double)$configuredPriceBlock->getPrice(); + $actualResult[] = $optionData; + } + } + + $expectedResult[] = [ + 'qty' => $assignedProduct['data']['selection_qty'], + 'name' => $assignedProduct['search_data']['name'], + 'price' => $assignedProductQty * $assignedProductPrice + (double)$product->getPrice() + ]; + } + } + + \PHPUnit_Framework_Assert::assertEquals( + $expectedResult, + $actualResult, + 'Bundle Summary Section does not contain correct bundle options data.' + ); + } + + /** + * Extract Bundle summary item Qty and Name from row text. + * + * @param string $rowItem + * @return array + */ + private function getBundleOptionData($rowItem) + { + // Row item must be displayed like "1 x Simple Product". + $rowItem = explode(' x ', $rowItem); + return [ + 'qty' => $rowItem[0], + 'name' => $rowItem[1] + ]; + } + + /** + * Return Text if displayed on frontend equals with fixture. + * + * @return string + */ + public function toString() + { + return 'Bundle options are displayed correctly in the summary section.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionTitleOnStorefront.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionTitleOnStorefront.php new file mode 100644 index 0000000000000..3da841feb7e98 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionTitleOnStorefront.php @@ -0,0 +1,68 @@ +open(); + $cmsIndex->getLinksBlock()->waitWelcomeMessage(); + foreach ($stores as $store) { + $cmsIndex->getStoreSwitcherBlock()->selectStoreView($store->getName()); + $cmsIndex->getLinksBlock()->waitWelcomeMessage(); + $browser->open($_ENV['app_frontend_url'] . $originalProduct->getUrlKey() . '.html'); + $catalogProductView->getBundleViewBlock()->clickCustomize(); + \PHPUnit_Framework_Assert::assertTrue( + $catalogProductView->getBundleViewBlock()->getBundleBlock()->isOptionVisible( + $optionTitles[$store->getStoreId()] + ), + sprintf( + 'Option with title \'%s\' is missing in \'%s\' store view.', + $optionTitles[$store->getStoreId()], + $store->getName() + ) + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Option title is correct on product view page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php new file mode 100644 index 0000000000000..5775b3597d9f8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php @@ -0,0 +1,78 @@ + $product->getSku()]; + $productGrid->open(); + $productGrid->getProductGrid()->searchAndOpen($filter); + + $productData = $product->getData()['bundle_selections']['bundle_options']; + $originalProductData = $originalProduct->getData()['bundle_selections']['bundle_options']; + $formData = $productPage->getProductForm()->getData($product)['bundle_selections']; + + $productDataLength = count($productData); + $formDataLength = count($productData); + \PHPUnit_Framework_Assert::assertEquals($productDataLength, $formDataLength); + + foreach ($productData as $index => $option) { + $productAssociatedDataLength = count($option['assigned_products']); + $formAssociatedDataLength = count($formData[$index]['assigned_products']); + \PHPUnit_Framework_Assert::assertEquals($productAssociatedDataLength, $formAssociatedDataLength); + + foreach ($option['assigned_products'] as $productIndex => $associatedProduct) { + $associatedProduct['data']['getProductName'] = + $originalProductData[$index+1]['assigned_products'][$productIndex]['search_data']['name']; + $associatedProduct = $associatedProduct['data']; + $errorAssociatedProducts = array_diff( + $associatedProduct, + $formData[$index]['assigned_products'][$productIndex] + ); + \PHPUnit_Framework_Assert::assertCount(0, $errorAssociatedProducts); + } + + unset($option['assigned_products']); + unset($formData[$index]['assigned_products']); + $errorFields = array_diff($option, $formData[$index]); + \PHPUnit_Framework_Assert::assertCount(0, $errorFields); + } + } + + /** + * Returns a string representation of the object + * + * @return string + */ + public function toString() + { + return 'Bundle options were not deleted correctly. There is difference with expected options'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php new file mode 100644 index 0000000000000..db44ab89e776e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php @@ -0,0 +1,64 @@ +create(ConfigureProductOnProductPageStep::class, ['product' => $product])->run(); + + //Process assertions + $this->assertPrice($product, $catalogProductView); + } + + /** + * Assert prices on the product view Page. + * + * @param BundleProduct $product + * @param CatalogProductView $productView + * @return void + */ + protected function assertPrice(BundleProduct $product, CatalogProductView $productView) + { + $checkoutData = $product->getCheckoutData(); + \PHPUnit_Framework_Assert::assertEquals( + $checkoutData['cartItem']['configuredPrice'], + $productView->getBundleViewBlock()->getBundleSummaryBlock()->getConfiguredPriceBlock()->getPrice(), + 'Bundle price calculated is not correct.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Bundle price calculates right on product view page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php index 58ad7a349fb66..715da71e0f442 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php @@ -1,6 +1,6 @@ countSubItemPrice($product); + } + + /** + * Count subItem price. + * + * @param FixtureInterface $product + * @return void + */ + private function countSubItemPrice(FixtureInterface $product) + { + $checkoutData = $product->getCheckoutData(); + if (isset($checkoutData['cartItem']['subItemPrice'])) { + $this->fixtureActualPrice += $checkoutData["cartItem"]["subItemPrice"]; + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductInCustomerWishlistOnBackendGrid.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductInCustomerWishlistOnBackendGrid.php index b2ca62bdc507b..368b34740277c 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductInCustomerWishlistOnBackendGrid.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductInCustomerWishlistOnBackendGrid.php @@ -1,6 +1,6 @@ product->hasData('special_price')) { + return null; + } + + $priceBlock = $this->productView->getPriceBlock(); + + if (!$priceBlock->isVisible()) { + return "Price block for '{$this->product->getName()}' product' is not visible."; + } + + if (!$priceBlock->isOldPriceVisible()) { + return 'Bundle special price is not set.'; + } + + $regularPrice = $priceBlock->getOldPrice(); + $priceData = $this->product->getDataFieldConfig('price')['source']->getPriceData(); + + if (!isset($priceData['regular_from'])) { + return 'Regular from price not set.'; + } + + if ($priceData['regular_from'] != $regularPrice) { + return 'Bundle regular price on product view page is not correct.'; + } + + return null; + } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertProductCustomOptionsOnBundleProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertProductCustomOptionsOnBundleProductPage.php index 084566ff1d6ff..5bbcfed20b767 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertProductCustomOptionsOnBundleProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertProductCustomOptionsOnBundleProductPage.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct/BundleSelections.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct/BundleSelections.php index f72258c45ad35..97179f65667c1 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct/BundleSelections.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/BundleProduct/BundleSelections.php @@ -1,6 +1,6 @@ data['products']; + } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php index cb46e728191bf..80a6eb62a795c 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Fixture/Cart/Item.php @@ -1,14 +1,11 @@ getBundleSelections(); - $checkoutData = $product->getCheckoutData(); + parent::getData($key); + $bundleSelection = $this->product->getBundleSelections(); + $checkoutData = $this->product->getCheckoutData(); $checkoutBundleOptions = isset($checkoutData['options']['bundle_options']) ? $checkoutData['options']['bundle_options'] : []; + $productSku = [$this->product->getSku()]; foreach ($checkoutBundleOptions as $checkoutOptionKey => $checkoutOption) { - // Find option and value keys - $attributeKey = null; - $optionKey = null; - foreach ($bundleSelection['bundle_options'] as $key => $option) { - if ($option['title'] == $checkoutOption['title']) { - $attributeKey = $key; - - foreach ($option['assigned_products'] as $valueKey => $value) { - if (false !== strpos($value['search_data']['name'], $checkoutOption['value']['name'])) { - $optionKey = $valueKey; - } - } - } - } - + $keys = $this->getKeys($bundleSelection['bundle_options'], $checkoutOption); + $attributeKey = $keys['attribute']; + $optionKey = $keys['option']; // Prepare option data $bundleSelectionAttribute = $bundleSelection['products'][$attributeKey]; $bundleOptions = $bundleSelection['bundle_options'][$attributeKey]; $value = $bundleSelectionAttribute[$optionKey]->getName(); + $this->product->getSkuType() == 'No' ?: $productSku[] = $bundleSelectionAttribute[$optionKey]->getSku(); $qty = $bundleOptions['assigned_products'][$optionKey]['data']['selection_qty']; - $price = $product->getPriceType() == 'Yes' + $price = $this->product->getPriceType() == 'Yes' ? number_format($bundleSelectionAttribute[$optionKey]->getPrice(), 2) : number_format($bundleOptions['assigned_products'][$optionKey]['data']['selection_price_value'], 2); $optionData = [ @@ -64,6 +51,47 @@ public function __construct(FixtureInterface $product) $checkoutBundleOptions[$checkoutOptionKey] = $optionData; } + $this->data['sku'] = implode('-', $productSku); $this->data['options'] += $checkoutBundleOptions; + + return $this->data; + } + + /** + * Get option key. + * + * @param array $assignedProducts + * @param string $checkoutOption + * @return null|string + */ + private function getOptionKey(array $assignedProducts, $checkoutOption) + { + foreach ($assignedProducts as $key => $value) { + if (false !== strpos($value['search_data']['name'], $checkoutOption)) { + return $key; + } + } + + return null; + } + + /** + * Find option and attribute keys. + * + * @param array $bundleOptions + * @param string $checkoutOption + * @return array + */ + private function getKeys(array $bundleOptions, $checkoutOption) + { + $keys = []; + foreach ($bundleOptions as $key => $option) { + if ($option['title'] == $checkoutOption['title']) { + $keys['attribute'] = $key; + $keys['option'] = $this->getOptionKey($option['assigned_products'], $checkoutOption['value']['name']); + } + } + + return $keys; } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/BundleProductInterface.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/BundleProductInterface.php index 1e3b74565dc42..c573ab9423c56 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/BundleProductInterface.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/BundleProductInterface.php @@ -1,6 +1,6 @@ [ 'Yes' => 1, 'No' => 0 + ], + 'user_defined' => [ + 'Yes' => 1, + 'No' => 0 ] ]; } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php index 634f6c00a6cc8..1219a0753e5dd 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Handler/BundleProduct/Webapi.php @@ -1,6 +1,6 @@ $bundleOption['title'], 'type' => $bundleOption['type'], 'required' => $bundleOption['required'], - 'product_links' => [], + 'product_links' => $this->prepareLinksInfo($bundleSelections, $key) ]; - - $productLinksInfo = $bundleOption['assigned_products']; - $products = $bundleSelections['products'][$key]; - foreach ($productLinksInfo as $linkKey => $productLink) { - $product = $products[$linkKey]; - $bundleProductOptions[$key]['product_links'][] = [ - 'sku' => $product->getSku(), - 'qty' => $productLink['data']['selection_qty'], - 'is_default' => false, - 'price' => isset($productLink['data']['selection_price_value']) - ? $productLink['data']['selection_price_value'] - : null, - 'price_type' => isset($productLink['data']['selection_price_type']) - ? $productLink['data']['selection_price_type'] - : null, - ]; - } } } @@ -92,6 +75,39 @@ protected function prepareBundleItems() unset($this->fields['product']['bundle_selections']); } + /** + * Prepare links info field. + * + * @param array $bundleSelections + * @param int $key + * @return array + */ + private function prepareLinksInfo(array $bundleSelections, $key) + { + $result = []; + $productLinksInfo = $bundleSelections['bundle_options'][$key]['assigned_products']; + $products = $bundleSelections['products'][$key]; + foreach ($productLinksInfo as $linkKey => $productLink) { + $product = $products[$linkKey]; + $result[] = [ + 'sku' => $product->getSku(), + 'qty' => $productLink['data']['selection_qty'], + 'is_default' => false, + 'price' => isset($productLink['data']['selection_price_value']) + ? $productLink['data']['selection_price_value'] + : null, + 'price_type' => isset($productLink['data']['selection_price_type']) + ? $productLink['data']['selection_price_type'] + : null, + 'can_change_quantity' => isset($productLink['data']['user_defined']) + ? $productLink['data']['user_defined'] + : 0, + ]; + } + + return $result; + } + /** * Parse response. * diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/CustomerIndexEdit.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/CustomerIndexEdit.xml index 6b546e6565d83..82a94ac02bbf0 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/CustomerIndexEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/CustomerIndexEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/OrderCreateIndex.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/OrderCreateIndex.xml index efd31aaf10278..e4c1d968c8303 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/OrderCreateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Adminhtml/OrderCreateIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Product/CatalogProductView.xml index ff1e036a93802..955da7ae385d9 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml index 2b5e9a437b32b..075f08c9b0092 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct.xml @@ -1,7 +1,7 @@ @@ -29,6 +29,28 @@ + + Bundle dynamic product %isolation% + bundle-dynamic-product-%isolation% + sku_bundle_dynamic_product_%isolation% + Yes + Yes + + In Stock + + + bundle_dynamic_with_category + + + + default + + + + one_simple_product + + + Bundle dynamic product %isolation% sku_bundle_dynamic_product_%isolation% @@ -184,6 +206,34 @@ bundle_required_two_fixed_options + + + Bundle fixed product %isolation% + bundle-fixed-product-%isolation% + sku_bundle_fixed_product_%isolation% + No + No + + 100 + + + taxable_goods + + 1 + No + + + default + + + Separately + + required_three_fixed_options_with_qty + + + bundle_required_three_fixed_options_with_qty + + Bundle fixed product %isolation% @@ -225,5 +275,109 @@ bundle_fixed_100_dollar + + + Bundle fixed product %isolation% + sku_bundle_fixed_product_%isolation% + No + No + + 100 + fixed_100_dollar + + + taxable_goods + + + In Stock + + 1 + No + Yes + Together + + + default + + + + Yes + Yes + Yes + In Stock + + bundle-fixed-product-%isolation% + Catalog, Search + + fixed_100_dollar_buy_all + + Default + + bundle_fixed_100_dollar_buy_all + + + + + Bundle with 3 options %isolation% + with_3_bundle_options-%isolation% + sku_with_3_bundle_options_%isolation% + No + No + + 100 + + + taxable_goods + + + + default + + + + with_3_options + + + + + Bundle low stock product %isolation% + sku_bundle_low_stock_product_%isolation% + No + No + + 750 + default_fixed + + + taxable_goods + + + In Stock + + 1 + No + Yes + Together + + + default + + + + Yes + Yes + Yes + In Stock + + bundle-fixed-product-%isolation% + Catalog, Search + + low_stock_fixed + + Default + + bundle_low_stock_fixed + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml index 0b142044323d1..29453db583295 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/BundleSelections.xml @@ -1,7 +1,7 @@ @@ -12,6 +12,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -41,11 +42,75 @@ + + + + Drop-down Option + Drop-down + Yes + + + + %product_name% + + + 1 + + + + + + + + catalogProductSimple::default + + + + Drop-down Option Drop-down + Drop-down + Yes + + + + %product_name% + + + 5.00 + Fixed + 1 + + + + + %product_name% + + + 6.00 + Fixed + 1 + + + + + + + + catalogProductSimple::default + catalogProductSimple::product_100_dollar + + + + + + + + Custom Option %isolation% + Drop-down Yes @@ -84,6 +149,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -117,11 +183,50 @@ + + + + Drop-down Option + Drop-down + Yes + + + + %product_name% + + + 10.00 + Fixed + 1 + + + + + %product_name% + + + 560.00 + Fixed + 1 + + + + + + + + catalogProductSimple::default_qty_1 + catalogProductSimple::out_of_stock + + + + Drop-down Option Drop-down + Drop-down Yes @@ -150,7 +255,7 @@ catalogProductSimple::default - catalogProductSimple::product_100_dollar + catalogProductSimple::product_10_dollar @@ -160,6 +265,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -187,6 +293,7 @@ Radio Button Option Radio Buttons + Radio Buttons Yes @@ -214,6 +321,7 @@ Checkbox Option Checkbox + Checkbox Yes @@ -241,6 +349,7 @@ Multiple Select Option Multiple Select + Multiple Select Yes @@ -291,6 +400,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -314,6 +424,7 @@ Radio Button Option Radio Buttons + Radio Buttons Yes @@ -337,6 +448,7 @@ Checkbox Option Checkbox + Checkbox Yes @@ -360,6 +472,7 @@ Multiple Select Option Multiple Select + Multiple Select Yes @@ -406,6 +519,7 @@ Drop-down Option Drop-down + Drop-down No @@ -433,6 +547,7 @@ Radio Button Option Radio Buttons + Radio Buttons No @@ -475,6 +590,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -513,6 +629,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -547,6 +664,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -572,6 +690,7 @@ Drop-down Option Drop-down + Drop-down Yes @@ -604,5 +723,348 @@ + + + + + Drop-down Option + Drop-down + Drop-down + Yes + + + + %product_name% + + + 10.00 + Fixed + 1 + + + + + %product_name% + + + 20.00 + Fixed + 2 + + + + + %product_name% + + + 30.00 + Fixed + 3 + + + + + + + + catalogProductSimple::simple + catalogProductSimple::product_15_dollar + catalogProductSimple::product_40_dollar + + + + + + + + Drop-down Option + Drop-down + Drop-down + Yes + + + + %product_name% + + + 1 + + + + + %product_name% + + + 1 + + + + + + Drop-down Option + Drop-down + Drop-down + Yes + + + + %product_name% + + + 1 + + + + + %product_name% + + + 1 + + + + + + + + catalogProductSimple::product_10_dollar + catalogProductSimple::product_with_special_price + + + catalogProductSimple::product_10_dollar + catalogProductSimple::product_with_special_price + + + + + + + + Option 1 + Drop-down + No + + + + %product_name% + + + 1 + 1 + Fixed + + + + + + Option 2 + Radio Buttons + No + + + + %product_name% + + + 20 + 20 + Fixed + + + + + %product_name% + + + 21 + 21 + Fixed + + + + + %product_name% + + + 22 + 22 + Fixed + + + + + + Option 3 + Drop-down + No + + + + %product_name% + + + 3 + 3 + Fixed + + + + + + + + catalogProductSimple::default + + + catalogProductSimple::default + catalogProductSimple::product_100_dollar + catalogProductSimple::product_without_category + + + catalogProductSimple::default + + + + + + + + Option 1 + Drop-down + No + + + + + Option 2 + Radio Buttons + No + + + + %product_name% + + + 20 + 20 + Fixed + + + + + %product_name% + + + 21 + 21 + Fixed + + + + + %product_name% + + + 22 + 22 + Fixed + + + + + + Option 3 + Drop-down + No + + + + %product_name% + + + 3 + 3 + Fixed + + + + + + + + catalogProductSimple::default + catalogProductSimple::product_100_dollar + catalogProductSimple::product_without_category + + + catalogProductSimple::default + + + + + + + + Drop-down Option + Drop-down + Hidden + Yes + + + + %product_name% + + + 1 + Yes + + + + + + + + catalogProductSimple::default + + + + + + + + Drop-down Option + Drop-down + Yes + + + + %product_name% + + + 5.00 + Fixed + 1 + + + + + %product_name% + + + 6.00 + Fixed + 1 + + + + + + + + catalogProductSimple::default + catalogProductSimple::low_stock_product + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml index 3cc61abfd2e89..f36f621931feb 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/CheckoutData.xml @@ -1,7 +1,7 @@ @@ -13,6 +13,7 @@ Drop-down Option Drop-down + Drop-down product_100_dollar @@ -27,6 +28,7 @@ Drop-down Option Drop-down + Drop-down product_100_dollar @@ -47,6 +49,7 @@ Drop-down Option Drop-down + Drop-down product_100_dollar @@ -67,6 +70,7 @@ Drop-down Option Drop-down + Drop-down product_10_dollar @@ -81,12 +85,34 @@ + + + + + Drop-down Option + Drop-down + true + + default_qty_1 + + + + + 1 + + 110 + 1 + 110 + + + Drop-down Option Drop-down + Drop-down Simple Product @@ -95,9 +121,9 @@ 1 - 756 + 755 1 - 756 + 755 @@ -107,6 +133,7 @@ Drop-down Option Drop-down + Drop-down product_100_dollar @@ -114,6 +141,7 @@ Radio Button Option Radio Buttons + Radio Buttons product_100_dollar @@ -128,6 +156,7 @@ Drop-down Option Drop-down + Drop-down product_100_dollar @@ -192,6 +221,7 @@ Drop-down Option Drop-down + Drop-down product_100_dollar @@ -206,12 +236,44 @@ + + + + + Drop-down Option + Drop-down + Drop-down + + product_10_dollar + + + + + + attribute_key_0 + option_key_0 + + + attribute_key_1 + option_key_0 + + + + + 100 + 1 + 100 + 10 + + + Drop-down Option Drop-down + Drop-down product_100_dollar @@ -219,6 +281,7 @@ Radio Button Option Radio Buttons + Radio Buttons product_100_dollar @@ -226,6 +289,7 @@ Checkbox Option Checkbox + Checkbox product_100_dollar @@ -233,6 +297,7 @@ Multiple Select Option Multiple + Multiple product_100_dollar @@ -285,6 +350,7 @@ Drop-down Option Drop-down + Drop-down product_100_dollar @@ -292,6 +358,7 @@ Radio Button Option Radio Buttons + Radio Buttons product_100_dollar @@ -299,6 +366,7 @@ Checkbox Option Checkbox + Checkbox product_100_dollar @@ -306,6 +374,7 @@ Multiple Select Option Multiple + Multiple product_100_dollar @@ -320,6 +389,61 @@ Drop-down Option Drop-down + Drop-down + + Test simple product + + + + + + + + + + + Drop-down Option + Drop-down + Hidden + + Simple Product + 3 + + + + + + 1680 + + + + + + + + Drop-down Option + Drop-down + + low_stock_product + + + + + 1 + + 756 + 1 + 756 + + + + + + + + Drop-down Option + Drop-down + Drop-down Test simple product diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml index c6b69dd6937d9..70bc732774523 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Repository/BundleProduct/Price.xml @@ -1,7 +1,7 @@ @@ -78,6 +78,18 @@ 756.00 + + 51.00 + 52.00 + 135.00 + + + + 785.00 + 786.00 + 786.00 + + 130.00 144.00 @@ -94,6 +106,12 @@ 8.00 20.00 80.00 + 40.00 + + + + 18.00 + 20.00 diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/BundleOptionsSummaryTest.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/BundleOptionsSummaryTest.php new file mode 100644 index 0000000000000..57daa9f474917 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/BundleOptionsSummaryTest.php @@ -0,0 +1,34 @@ +persist(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/BundleOptionsSummaryTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/BundleOptionsSummaryTest.xml new file mode 100644 index 0000000000000..99e7bf6510d9d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/BundleOptionsSummaryTest.xml @@ -0,0 +1,17 @@ + + + + + + severity:S2 + Bundle Option with Three Drop-Down selections with qty + fixed_with_required_options_and_qty + + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.php index ac2c977f88b83..15dce2c9efc63 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/CreateBundleProductEntityTest.php @@ -1,6 +1,6 @@ + stable:no Create default bundle with dynamic options bundle-product-%isolation% BundleProduct %isolation% @@ -44,7 +45,7 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, to_maintain:yes Create dynamic bundle with price randle and all types options bundle-product-%isolation% BundleProduct %isolation% @@ -73,7 +74,7 @@ - + Create fixed bundle bundle-product-%isolation% BundleProduct %isolation% @@ -87,7 +88,7 @@ 10 Bundle Product Fixed Required default_fixed - catalogProductSimple::product_100_dollar,catalogProductVirtual::product_50_dollar + catalogProductSimple::product_100_dollar,catalogProductSimple::out_of_stock bundle_default @@ -97,6 +98,7 @@ + stable:no Create fixed bundle with all types options bundle-product-%isolation% BundleProduct %isolation% @@ -160,7 +162,8 @@ - + + to_maintain:yes bundle-product-%isolation% BundleProduct %isolation% Yes @@ -187,6 +190,7 @@ + to_maintain:yes Create dynamic bundle with special price bundle-product-%isolation% Bundle Dynamic %isolation% @@ -195,8 +199,8 @@ Yes dynamic-8 20 - M j, Y -1 day - M j, Y +3 days + m/d/y -1 day + m/d/y +3 days default_dynamic catalogProductSimple::product_100_dollar,catalogProductSimple::product_40_dollar bundle_default @@ -236,6 +240,7 @@ + MAGETWO-52788: Dynamic Rows: support status being changed Create fixed product with checkout first option bundle-product-%isolation% Bundle Fixed %isolation% @@ -333,5 +338,133 @@ + + stable:no + bundle-product-%isolation% + Bundle Fixed %isolation% + No + sku_bundle_fixed_%isolation% + No + 100 + fixed-100 + No + 10 + default + As Low as + No + No + Together + second + percent_and_fixed_drop_down_options + bundle_with_custom_options_3 + + + + + + + + + stable:no + bundle-product-%isolation% + BundleProduct %isolation% + Yes + bundle_sku_%isolation% + Yes + dynamic-50 + No + 10 + default + As Low as + No + No + Together + default_dynamic + catalogProductSimple::simple_with_tier_price,catalogProductVirtual::product_50_dollar + bundle_default + Search + + + + + + + bundle-product-%isolation% + BundleProduct %isolation% + bundle_sku_%isolation% + Yes + dynamic-50 + default_dynamic + catalogProductSimple::out_of_stock,catalogProductSimple::out_of_stock + bundle_default + + + + + to_maintain:yes + bundle-product-%isolation% + Bundle Fixed %isolation% + No + sku_bundle_fixed_%isolation% + No + 10 + second + catalogProductSimple::product_100_dollar,catalogProductSimple::product_40_dollar + bundle_default + custom_store + + + + + bundle-product-%isolation% + Bundle Fixed %isolation% + No + sku_bundle_fixed_%isolation% + No + 100 + fixed-51 + Price Range + 20 + second + drop_down_with_one_option_fixed_price + + + + + bundle-product-%isolation% + Bundle Dynamic %isolation% + Yes + sku_bundle_dynamic_%isolation% + Yes + dynamic-8 + 20 + default_dynamic + catalogProductSimple::product_100_dollar,catalogProductSimple::product_40_dollar + + + + + bundle-product-%isolation% + Bundle Dynamic %isolation% + Yes + sku_bundle_dynamic_%isolation% + Yes + dynamic-18 + dynamic_with_two_required_options_assigned_products_with_special_price + + + + + bundle-product-%isolation% + Bundle Dynamic %isolation% + sku_bundle_dynamic_%isolation% + Yes + category_%isolation% + Together + one_required_option_with_one_item + one_required_option_with_one_item + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductEntityTest.xml index 08f6d75daf422..66917983cfe2d 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductEntityTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml index 7a64aa897ddb8..dcd75d3cadac1 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml new file mode 100644 index 0000000000000..640f5b1e904d8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -0,0 +1,17 @@ + + + + + + bundleProduct::bundle_dynamic_product + bundleProduct::bundle_dynamic_product + true + + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.php new file mode 100644 index 0000000000000..966475796da07 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.php @@ -0,0 +1,94 @@ +Inventory>Catalog + * 3. Click on Bundle product in the grid to edit it + * 4. Fill in some Bundle Options data according to data set + * 5. Delete some Bundle Options data according to data set + * 6. Save product + * 7. Verify Bundle Options in the updated product + * + * @group Bundle_Product + * @ZephyrId MAGETWO-26195 + */ +class UpdateBundleOptionsTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + /* end tags */ + + /** + * Page product on backend + * + * @var CatalogProductIndex + */ + protected $catalogProductIndex; + + /** + * Edit page on backend + * + * @var CatalogProductEdit + */ + protected $catalogProductEdit; + + /** + * Injection data + * + * @param CatalogProductIndex $catalogProductIndexNewPage + * @param CatalogProductEdit $catalogProductEditPage + * @return void + */ + public function __inject( + CatalogProductIndex $catalogProductIndexNewPage, + CatalogProductEdit $catalogProductEditPage + ) { + $this->catalogProductIndex = $catalogProductIndexNewPage; + $this->catalogProductEdit = $catalogProductEditPage; + } + + /** + * Test update bundle product + * + * @param BundleProduct $product + * @param BundleProduct $originalProduct + * @return void + */ + public function test(BundleProduct $product, BundleProduct $originalProduct) + { + // Preconditions + $originalProduct->persist(); + + // Steps + $filter = ['sku' => $originalProduct->getSku()]; + + $this->catalogProductIndex->open(); + $this->catalogProductIndex->getProductGrid()->searchAndOpen($filter); + + $form = $this->catalogProductEdit->getProductForm(); + $form->openSection('bundle'); + $container = $form->getSection('bundle'); + $containerFields = $product->getData()['bundle_selections']['bundle_options_delete']; + $container->deleteFieldsData($containerFields); + + $form->openSection('product-details'); + $container = $form->getSection('product-details'); + $containerFields = $product->getData(); + unset($containerFields['bundle_selections']); + $container->setFieldsData($containerFields); + + $this->catalogProductEdit->getFormPageActions()->save(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.xml new file mode 100644 index 0000000000000..4a25fa616510f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleOptionsTest.xml @@ -0,0 +1,19 @@ + + + + + + Update bundle product options + with_3_bundle_options + bundle_3_options_%isolation% + bundle_3_options_%isolation% + with_3_options_delete + + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.php index bf17d216bcf9b..9814bbd84e1ac 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.php @@ -1,15 +1,17 @@ catalogProductIndex = $catalogProductIndexNewPage; $this->catalogProductEdit = $catalogProductEditPage; + $this->fixtureFactory = $fixtureFactory; } /** - * Test update bundle product + * Test update bundle product. * * @param BundleProduct $product * @param BundleProduct $originalProduct + * @param Store|null $store * @return array */ - public function test(BundleProduct $product, BundleProduct $originalProduct) - { + public function test( + BundleProduct $product, + BundleProduct $originalProduct, + Store $store = null + ) { // Preconditions $originalProduct->persist(); - $originalCategory = $originalProduct->hasData('category_ids') - ? $originalProduct->getDataFieldConfig('category_ids')['source']->getCategories() - : null; - $category = $product->hasData('category_ids') - ? $product->getDataFieldConfig('category_ids')['source']->getCategories() - : $originalCategory; + $category = $this->getCategories($originalProduct, $product); + + if ($store) { + $store->persist(); + $optionTitle[$store->getStoreId()] = $product->getBundleSelections()['bundle_options'][0]['title']; + } // Steps $filter = ['sku' => $originalProduct->getSku()]; $this->catalogProductIndex->open(); $this->catalogProductIndex->getProductGrid()->searchAndOpen($filter); + if ($store) { + $this->catalogProductEdit->getFormPageActions()->changeStoreViewScope($store); + } $this->catalogProductEdit->getProductForm()->fill($product); $this->catalogProductEdit->getFormPageActions()->save(); - return ['category' => $category]; + return [ + 'category' => $category, + 'stores' => isset($store) ? [$store] : [], + 'optionTitles' => isset($optionTitle) ? $optionTitle : [] + ]; + } + + /** + * Get Category instances. + * + * @param BundleProduct $originalProduct + * @param BundleProduct $product + * @return array + */ + protected function getCategories(BundleProduct $originalProduct, BundleProduct $product) + { + $originalCategory = $originalProduct->hasData('category_ids') + ? $originalProduct->getDataFieldConfig('category_ids')['source']->getCategories() + : null; + return $product->hasData('category_ids') + ? $product->getDataFieldConfig('category_ids')['source']->getCategories() + : $originalCategory; } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml index 1f241c1e321be..9f12cd2533a52 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/UpdateBundleProductEntityTest.xml @@ -1,7 +1,7 @@ @@ -73,5 +73,22 @@ + + bundle_fixed_product + bundle-product-%isolation% + bundle_fixed_%isolation% + bundle_sku_%isolation% + fixed-756-custom-options + drop_down_with_one_option_fixed_price + + + + + bundle_fixed_product + custom + fixed_with_custom_title + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml index 09ce73b61ec65..372f96cdaf829 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/curl/di.xml index 33a264e9ecb20..69b1be76851f3 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/di.xml new file mode 100644 index 0000000000000..52f1c88f40fb7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/di.xml @@ -0,0 +1,27 @@ + + + + + + S2 + + + + + + + + \Magento\Bundle\Test\Block\Adminhtml\Product\Composite\Configure + //ancestor::body//*[contains(@class, "modal-slide") and contains(@class, "_show")] + xpath + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/webapi/di.xml index 192e616ef1534..c7cb9ab40dab9 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/AbstractConfigureBlock.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/AbstractConfigureBlock.php index 43d79aed44515..95ff476d544f5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/AbstractConfigureBlock.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/AbstractConfigureBlock.php @@ -1,6 +1,6 @@ \Magento\Ui\Test\Block\Adminhtml\Section - div[class=fieldset-wrapper] + [data-index="general"] css selector @@ -31,8 +31,8 @@ \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::select[@name='landing_page']] - xpath + [data-index="content"] + css selector textarea @@ -45,8 +45,8 @@ \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::input[@name='is_anchor']] - xpath + [data-index="display_settings"] + css selector select @@ -83,13 +83,17 @@ \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::input[@name='meta_title']] - xpath + [data-index="search_engine_optimization"] + css selector input input[name='url_key'] + + checkbox + input[name='use_default[url_key]'] + input input[name='meta_title'] @@ -98,13 +102,13 @@ \Magento\Catalog\Test\Block\Adminhtml\Category\Edit\Section\Products - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::div[@id='catalog_category_products']] - xpath + [data-index="assign_products"] + css selector \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::select[@name='page_layout']] - xpath + [data-index="design"] + css selector checkbox @@ -130,15 +134,15 @@ \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::input[@name='custom_design_to']] - xpath + [data-index="schedule_design_update"] + css selector - text + datepicker input[name='custom_design_from'] - text + datepicker input[name='custom_design_to'] diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php index 27e15044df11d..3adee2a605e96 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/PageActions.php @@ -1,18 +1,24 @@ click(); } } + + /** + * Select Store View. + * + * @param string $name + * @return void + */ + public function selectStoreView($name) + { + $this->browser->find(self::TOP_ELEMENT_TO_SCROLL)->hover(); + $this->_rootElement->find($this->storeChangeButton)->click(); + $this->waitForElementVisible($name, Locator::SELECTOR_LINK_TEXT); + $this->_rootElement->find($name, Locator::SELECTOR_LINK_TEXT)->click(); + $element = $this->browser->find($this->confirmModal); + /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ + $modal = $this->blockFactory->create(\Magento\Ui\Test\Block\Adminhtml\Modal::class, ['element' => $element]); + $modal->acceptAlert(); + $this->waitForElementVisible($this->storeChangeButton); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php index e05bf4af830b6..8d086230c14d0 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Edit/Section/ProductGrid.php @@ -1,6 +1,6 @@ isElementVisible($categoryPath); } + /** + * Assign child category to the parent. + * + * @param string $parentCategoryName + * @param string $childCategoryName + * + * @return void + */ + public function assignCategory($parentCategoryName, $childCategoryName) + { + $this->_rootElement->find(sprintf($this->categoryInTree, $childCategoryName), Locator::SELECTOR_XPATH)->click(); + $this->getTemplateBlock()->waitLoader(); + $targetElement = $this->_rootElement->find( + sprintf($this->categoryInTree, $parentCategoryName), + Locator::SELECTOR_XPATH + ); + $targetElement->hover(); + $this->_rootElement->find(sprintf($this->categoryInTree, $childCategoryName), Locator::SELECTOR_XPATH) + ->dragAndDrop($targetElement); + } + /** * Expand all categories tree. * * @return void */ - protected function expandAllCategories() + public function expandAllCategories() { $this->_rootElement->find($this->expandAll)->click(); } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Widget/Chooser.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Widget/Chooser.php index 60ace6d24e3f5..238edbd6220b9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Widget/Chooser.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Category/Widget/Chooser.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php index 53fe49b759c64..7968d453c9aec 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/CustomAttribute.php @@ -1,6 +1,6 @@ classReferences) as $key) { - if (strpos($class, $key) !== false) { + if ($class == $key) { return $this->classReferences[$class]; } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/AttributeForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/AttributeForm.php index a2db75f9bd058..20e18bea5a78c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/AttributeForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/AttributeForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php index 295a5be684b16..a0b29753a0324 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Edit/Options.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Grid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Grid.php index 8f64af8ac0900..8c56aa7f5cd75 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Set/Main/EditForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Set/Main/EditForm.php index e231e4c2c9d8c..ffebfae345291 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Set/Main/EditForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Attribute/Set/Main/EditForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Composite/Configure.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Composite/Configure.php index 23ed222dd0a9b..09b98c7d51810 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Composite/Configure.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Composite/Configure.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/Attribute.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/Attribute.xml deleted file mode 100644 index 59b367e49bd66..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/Attribute.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - attributes - - - [name='toggle_price'] - checkbox - - - - diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/FormPageActions.php index 057e26fb47be6..6754cb5c045b6 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/FormPageActions.php @@ -1,6 +1,6 @@ './/./ancestor::div[contains(@class,"control")]' + . '//input[@data-role="toggle-editability-all" or contains(@id, "toggle_")]', + 'strategy' => Locator::SELECTOR_XPATH, + 'input' => 'checkbox', + 'value' => 'Yes', + ]; + + /** + * Fill data into fields in the container. + * + * @param array $fields + * @param SimpleElement|null $contextElement + * @return $this + */ + public function setFieldsData(array $fields, SimpleElement $contextElement = null) + { + $context = ($contextElement === null) ? $this->_rootElement : $contextElement; + $mapping = $this->dataMapping($fields); + foreach ($mapping as $field) { + $this->_fill([$this->changeCheckbox], $context->find($field['selector'], $field['strategy'])); + $this->_fill([$field], $context); + } + + return $this; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/UpdateAttributeForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/UpdateAttributeForm.php new file mode 100644 index 0000000000000..4520f9bb8189e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Action/UpdateAttributeForm.php @@ -0,0 +1,17 @@ + + + + + Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Action\Tab\UpdateAttributeTab + #attributes_update_tabs_attributes + + + #price + + + + + Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Action\Tab\UpdateAttributeTab + #attributes_update_tabs_inventory + + + #inventory_stock_availability + select + + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedInventory.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedInventory.php index 42831a4a345b5..c6268904281a7 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedInventory.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedInventory.php @@ -1,6 +1,6 @@ @@ -10,6 +10,13 @@ [name$="[price]"] + + [name$="[value_type]"] + select + + + [name$="[percentage_value]"] + [name$="[website_id]"] select diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php index 68bf3fe0d5069..ba87ab1fbab7b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Attributes.php @@ -1,6 +1,6 @@ find($this->imageUploadInput, Locator::SELECTOR_CSS, 'upload'); + $uploadElement->setValue($imageData['file']); + $this->waitForElementNotVisible($this->imageLoader); + } + return $this; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php index 7cf367c57d214..00feb91c92ea3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.php index f1d588dd71fc4..692826e14a0b5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.php index da5ec52495abe..b94a7a3cfc8cd 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.php index d738e3c19b08b..7b2f10f03c27c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php index 0dfb865d05aae..88b2ec8ce4701 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.php index 18be9d08c5409..1832d1c3d6227 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.php index 6b1e3ee4c4c78..082bf8cb6fb67 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.php index 5ed31c669a682..6471a20a237e9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.php index 5ca14e350212a..7b0aa8f22e401 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.php index c7ae160e6330b..4774be3f74369 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php index 36765ef2cf4fd..e4615542269c2 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails.php @@ -1,6 +1,6 @@ browser->find($this->pageFooter)->isVisible()) { $this->browser->find($this->pageFooter)->hover(); $this->browser->find($this->advancedInventoryButton)->hover(); } - parent::setValue($value); + $this->eventManager->dispatchEvent(['set_value'], [__METHOD__, $this->getAbsoluteSelector()]); + + $this->clear(); + foreach ((array)$values as $value) { + if (!$this->isChoice($value)) { + if ($value == '') { + continue; + } + $this->keys([$value]); + $searchedItem = $this->find(sprintf($this->resultItem, $value), Locator::SELECTOR_XPATH); + $searchedItem->click(); + $closeButton = $this->find($this->closeButton); + if ($closeButton->isVisible()) { + $closeButton->click(); + } + } + } } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/NewCategoryIds.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/NewCategoryIds.php index 6c3887b660798..832f0f837fc7c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/NewCategoryIds.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/NewCategoryIds.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Related.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Related.php index 1616b7ca7172e..9f83826ee6627 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Related.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Related.php @@ -1,6 +1,6 @@ _rootElement->find($this->addAttribute)->click(); } + + /** + * Change Store View scope. + * + * @param FixtureInterface $store + * @return void + */ + public function changeStoreViewScope(FixtureInterface $store) + { + $this->waitForElementNotVisible($this->spinner); + $this->waitForElementVisible($this->storeSwitcherBlock); + $this->_rootElement->find($this->storeSwitcherBlock) + ->find($this->dropdownBlock, Locator::SELECTOR_CSS, 'liselectstore') + ->setValue(sprintf('%s/%s', $store->getGroupId(), $store->getName())); + $modalElement = $this->browser->find($this->confirmModal); + /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ + $modal = $this->blockFactory->create( + \Magento\Ui\Test\Block\Adminhtml\Modal::class, + ['element' => $modalElement] + ); + $modal->acceptAlert(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php index d5e81ad56fd32..668d8bbe9fbeb 100755 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php @@ -1,12 +1,13 @@ massaction($items, 'Update attributes'); + $products = []; + /** @var FixtureInterface $product */ + foreach ($items as $product) { + $products[] = ["sku" => $product->getSku()]; + } + $this->massaction($products, 'Update attributes'); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/GridPageAction.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/GridPageAction.php index 31428b08161d5..f5446ef33107c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/GridPageAction.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/GridPageAction.php @@ -1,6 +1,6 @@ callRender($typeId, 'fill', $renderArguments); } else { $sections = $this->getFixtureFieldsByContainers($product); - - if ($category) { - $sections['product-details']['category_ids']['value'] = $category->getName(); + if ($product->hasData('category_ids') || $category) { + $sections['product-details']['category_ids']['value'] = []; + $categories = $product->hasData('category_ids') + ? $product->getDataFieldConfig('category_ids')['source']->getCategories() + : [$category]; + foreach ($categories as $category) { + if ((int)$category->getId()) { + $sections['product-details']['category_ids']['value'][] = $category->getName(); + } else { + $this->getNewCategoryModalForm()->addNewCategory($category); + } + } + if (empty($sections['product-details']['category_ids']['value'])) { + // We need to clear 'category_ids' key in case of category(es) absence in Product Fixture + // to avoid force clear related form input on edit product page + unset($sections['product-details']['category_ids']); + } } $this->fillContainers($sections, $element); } @@ -193,6 +215,19 @@ public function getAttributeForm() ); } + /** + * Get New Category Modal Form. + * + * @return NewCategoryIds + */ + public function getNewCategoryModalForm() + { + return $this->blockFactory->create( + \Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\ProductDetails\NewCategoryIds::class, + ['element' => $this->browser->find($this->newCategoryModalForm)] + ); + } + /** * Get attribute element. * diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml index 407b5c9cb20a3..a787bc3485967 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.xml @@ -1,7 +1,7 @@ @@ -53,6 +53,14 @@ select + + [name="use_default[name]"] + checkbox + + + [name="use_default[price]"] + checkbox + @@ -143,7 +151,7 @@ - \Magento\Ui\Test\Block\Adminhtml\Section + \Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\BlockGallery [data-index='block_gallery'] css selector @@ -154,6 +162,10 @@ product + + [name="use_default[url_key]"] + checkbox + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Widget/Chooser.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Widget/Chooser.php index 5238ce35f1583..e6144d4e6b751 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Widget/Chooser.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Widget/Chooser.php @@ -1,6 +1,6 @@ getText(), $matches); return $matches[0][0]; } + + /** + * Wait for compare products link to appear + * + * @return void + */ + public function waitForCompareProductsLinks() + { + $this->waitForElementVisible($this->linkCompareProducts); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Additional.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Additional.php index a4f404dd1317a..ff24310accf76 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Additional.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Additional.php @@ -1,6 +1,6 @@ _rootElement->find(sprintf($this->removeButton, $index), Locator::SELECTOR_XPATH)->click(); + $modalElement = $this->browser->find($this->confirmModal); + /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ + $modal = $this->blockFactory->create( + \Magento\Ui\Test\Block\Adminhtml\Modal::class, + ['element' => $modalElement] + ); + $modal->acceptAlert(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php index 596dbd38664b3..7141cb5ef4881 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Compare/Sidebar.php @@ -1,6 +1,6 @@ _rootElement->find($this->clearAll)->click(); + $modalElement = $this->browser->find($this->confirmModal); + /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ + $modal = $this->blockFactory->create( + \Magento\Ui\Test\Block\Adminhtml\Modal::class, + ['element' => $modalElement] + ); + $modal->acceptAlert(); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Grouped/AssociatedProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Grouped/AssociatedProducts.php index 6846355b94ad1..0f51b7edaf9fa 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Grouped/AssociatedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Grouped/AssociatedProducts.php @@ -1,6 +1,6 @@ _rootElement->find($this->sorter)->getText()); + $values = explode("\n", $this->_rootElement->find($this->sorter)->getText()); + $result = []; + foreach ($values as $value) { + $result[] = trim($value); + } + return $result; } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php index 79cba4e681b9e..729aa0ed0be66 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php @@ -1,6 +1,6 @@ _rootElement->hover(); return $this->_rootElement->find($this->addToCard, Locator::SELECTOR_CSS)->isVisible(); } @@ -90,6 +91,7 @@ public function isVisibleAddToCardButton() */ public function clickAddToCart() { + $this->_rootElement->hover(); $this->_rootElement->find($this->addToCard, Locator::SELECTOR_CSS)->click(); } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php index 1ca480fb464af..60c58539660d5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/PromotedSection.php @@ -1,6 +1,6 @@ _rootElement->find("#sorter")->getElements('option[selected]')[0]->getText(); + $selectedOption = $this->_rootElement->find($this->sorter)->getElements('option[selected]')[0]->getText(); + preg_match('/\w+\s?\w+/', $selectedOption, $matches); + return $matches[0]; } /** - * Get all available method of sorting product + * Get all available method of sorting product. * - * @return array|string + * @return array */ public function getSortType() { - $content = str_replace("\r", '', $this->_rootElement->find($this->sorter)->getText()); + $content = $this->_rootElement->find($this->sorter)->getText(); return explode("\n", $content); } + + /** + * Apply sorting to the product list. + * + * @param array $sortBy + * @return void + */ + public function applySorting(array $sortBy) + { + if (!empty($sortBy['field'])) { + $this->_rootElement->find($this->sorter, Locator::SELECTOR_CSS, 'select')->setValue($sortBy['field']); + } + + if (!empty($sortBy['direction'])) { + $switcher = $this->_rootElement->find($this->direction); + if ($switcher->getAttribute('data-value') == $sortBy['direction']) { + $switcher->click(); + } + } + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Upsell.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Upsell.php index 4aa926748dddd..72625e6676d41 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Upsell.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/ProductList/Upsell.php @@ -1,6 +1,6 @@ _rootElement->find($this->thresholdMessage)->isVisible(); + } + + /** + * Gets threshold message. + * + * @return string + */ + public function getThresholdMessage() + { + return $this->_rootElement->find($this->thresholdMessage)->getText(); + } + /** * Get block price. * @@ -222,21 +256,44 @@ public function getPriceBlock() */ public function addToCart(FixtureInterface $product) { - /** @var \Magento\Checkout\Test\Block\Cart\Sidebar $miniCart */ - $miniCart = $this->blockFactory->create( - \Magento\Checkout\Test\Block\Cart\Sidebar::class, - ['element' => $this->browser->find($this->miniCartBlock)] - ); + $this->configure($product); + $this->clickAddToCart(); + $this->getMiniCartBlock()->waitLoader(); + } + + /** + * Configure Product. + * + * @param FixtureInterface $product + * @return void + */ + public function configure(FixtureInterface $product) + { /** @var CatalogProductSimple $product */ $checkoutData = $product->getCheckoutData(); - $miniCart->waitInit(); + $this->getMiniCartBlock()->waitInit(); $this->fillOptions($product); if (isset($checkoutData['qty'])) { $this->setQty($checkoutData['qty']); } - $this->clickAddToCart(); - $miniCart->waitLoader(); + } + + /** + * Get MiniCart block. + * + * @return Sidebar + */ + private function getMiniCartBlock() + { + if ($this->miniCartBlock === null) { + $this->miniCartBlock = $this->blockFactory->create( + Sidebar::class, + ['element' => $this->browser->find($this->miniCartBlockSelector)] + ); + } + + return $this->miniCartBlock; } /** @@ -313,14 +370,8 @@ public function inContextPaypalCheckout() public function braintreePaypalCheckout() { $currentWindow = $this->browser->getCurrentWindow(); - /** @var \Magento\Checkout\Test\Block\Cart\Sidebar $miniCart */ - $miniCart = $this->blockFactory->create( - \Magento\Checkout\Test\Block\Cart\Sidebar::class, - ['element' => $this->browser->find($this->miniCartBlock)] - ); - - $miniCart->openMiniCart(); - $miniCart->clickBraintreePaypalButton(); + $this->getMiniCartBlock()->openMiniCart(); + $this->getMiniCartBlock()->clickBraintreePaypalButton(); return $currentWindow; } @@ -498,14 +549,16 @@ public function waitLoader() } /** - * Check id media gallery is visible for the product. + * Check if media gallery is visible for the product. * * @return bool */ public function isGalleryVisible() { $this->waitForElementNotVisible($this->galleryLoader); - return $this->_rootElement->find($this->mediaGallery)->isVisible(); + $this->waitForElementVisible($this->mediaGallery); + + return true; } /** @@ -567,12 +620,19 @@ public function clickBaseImage() */ public function closeFullImage() { - $element = $this->browser->find($this->fullImageClose, Locator::SELECTOR_CSS); - if (!$element->isVisible()) { - $element->hover(); - $this->waitForElementVisible($this->fullImageClose); - } - $element->click(); + $this->_rootElement->waitUntil( + function () { + $this->browser->find($this->fullImage)->hover(); + + if ($this->browser->find($this->fullImageClose)->isVisible()) { + $this->browser->find($this->fullImageClose)->click(); + + return true; + } + + return null; + } + ); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php index bff1ecae73bf5..63da5eabe794b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php index 2fe1fecc99333..94183b9f4a08f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Search.php @@ -1,6 +1,6 @@ fillSearch($keyword); $this->_rootElement->find($this->searchButton)->click(); } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php index b2227e6515f46..20b3959a0b9ba 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php @@ -1,6 +1,6 @@ Inventory > Catalog). @@ -66,6 +75,7 @@ public function processAssert( CatalogProductEdit $catalogProductEdit, CatalogProductAttribute $attribute, CatalogAttributeSet $attributeSet, + BrowserInterface $browser, CatalogProductAttribute $productAttributeOriginal = null ) { $this->fixtureFactory = $fixtureFactory; @@ -92,9 +102,10 @@ public function processAssert( $catalogProductAttribute = ($productAttributeOriginal !== null) ? array_merge($productAttributeOriginal->getData(), $attribute->getData()) : $attribute->getData(); - if ($catalogProductEdit->getProductForm()->isSectionVisible(self::ATTRIBUTES)) { + if ($browser->find($this->attributes)->isVisible()) { $catalogProductEdit->getProductForm()->openSection(self::ATTRIBUTES); } + \PHPUnit_Framework_Assert::assertTrue( $catalogProductEdit->getProductForm()->checkAttributeLabel($catalogProductAttribute), "Product Attribute is absent on Product form." diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php index b0d5f2de6438a..4eb116552bbac 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php @@ -1,6 +1,6 @@ $product->getSku()]; + $catalogProductIndex->open()->getProductGrid()->searchAndOpen($filter); + $catalogProductEdit->getFormPageActions()->save(); + + \PHPUnit_Framework_Assert::assertNotEmpty( + $catalogProductEdit->getMessagesBlock()->getSuccessMessage(), + 'Can\'t save existing product.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product was saved without errors.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php index de3fc1a36c7d5..8c70af2a13cad 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php @@ -1,6 +1,6 @@ getMessagesBlock()->getSuccessMessage(); + \PHPUnit_Framework_Assert::assertEquals( + self::SUCCESS_MESSAGE, + $actualMessage, + 'Wrong success message is displayed.' + . "\nExpected: " . self::SUCCESS_MESSAGE + . "\nActual: " . $actualMessage + ); + } + + /** + * Success message is displayed. + * + * @return string + */ + public function toString() + { + return 'Success message is displayed.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomStore.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomStore.php new file mode 100644 index 0000000000000..284d9a83701f1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomStore.php @@ -0,0 +1,138 @@ +browser = $browser; + $this->categoryViewPage = $categoryView; + $this->cmsIndexPage = $cmsIndex; + + $this->verifyUnavailabilityCategoryOnMainStore($category); + $this->verifyAvailabilityCategoryOnMainStore($initialCategory); + $this->verifyCategoryOnCustomStore($category); + } + + /** + * Verify if category page is unavailable in Main Store. + * + * @param Category $category + * @return void + */ + private function verifyUnavailabilityCategoryOnMainStore(Category $category) + { + $this->browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); + + \PHPUnit_Framework_Assert::assertEquals( + self::NOT_FOUND_MESSAGE, + $this->categoryViewPage->getTitleBlock()->getTitle(), + 'Category ' . $category->getName() . ' is available on Main Store, but should not.' + ); + } + + /** + * Verify if category page is available in Main Store. + * + * @param Category $category + * @return void + */ + private function verifyAvailabilityCategoryOnMainStore(Category $category) + { + $this->browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); + + \PHPUnit_Framework_Assert::assertEquals( + $category->getName(), + $this->categoryViewPage->getTitleBlock()->getTitle(), + 'Category ' . $category->getName() . ' is not available on Main Store, but should.' + ); + } + + /** + * Verify Category is present in custom store. + * + * @param Category $category + * @return void + */ + private function verifyCategoryOnCustomStore(Category $category) + { + $this->cmsIndexPage->getStoreSwitcherBlock()->selectStoreView($category->getStoreId()['source']->getName()); + $this->cmsIndexPage->getLinksBlock()->waitWelcomeMessage(); + + $this->browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); + + \PHPUnit_Framework_Assert::assertEquals( + $category->getName(), + $this->categoryViewPage->getTitleBlock()->getTitle(), + 'Category ' . $category->getName() . ' is not available on custom store.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Category displayed in appropriate store.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomWebsite.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomWebsite.php new file mode 100644 index 0000000000000..aca1e562a7cf4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomWebsite.php @@ -0,0 +1,78 @@ +createByCode( + 'storeGroup', + [ + 'dataset' => 'custom_new_group', + 'data' => [ + 'root_category_id' => [ + 'category' => $category->getDataFieldConfig('parent_id')['source']->getParentCategory() + ] + ] + ] + ); + $storeGroup->persist(); + $store = $fixtureFactory->createByCode( + 'store', + [ + 'dataset' => 'custom_store', + 'data' => [ + 'group_id' => [ + 'storeGroup' => $storeGroup + ] + ] + ] + ); + $store->persist(); + + $websiteCode = $storeGroup->getDataFieldConfig('website_id')['source']->getWebsite()->getData('code'); + $browser->open($_ENV['app_frontend_url'] . 'websites/' . $websiteCode . '/' . $category->getName() . '.html'); + \PHPUnit_Framework_Assert::assertEquals( + $category->getName(), + $categoryView->getTitleBlock()->getTitle(), + 'Wrong category name is displayed on custom website store.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Category name is correct on custom website store.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php index 9884d0c3f4115..0ce432b86dd34 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php @@ -1,6 +1,6 @@ getMessagesBlock()->getSuccessMessage(); \PHPUnit_Framework_Assert::assertEquals( $expectedMessage, diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPriceOnProductPageInterface.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPriceOnProductPageInterface.php index 90409980d4557..6123e6409ae89 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPriceOnProductPageInterface.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPriceOnProductPageInterface.php @@ -1,6 +1,6 @@ $product->getSku()]; + $productGrid->open(); + $productGrid->getProductGrid()->search($filter); + $src = $productGrid->getProductGrid()->getBaseImageSource(); + \PHPUnit_Framework_Assert::assertTrue( + strpos($src, '/placeholder/') === false, + 'Product image is not present in product grid when it should be' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product image is displayed in product grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php index 85514109053b4..f2f4527094b5a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php @@ -1,6 +1,6 @@ getMessagesBlock()->waitSuccessMessage(); // Check price - $this->assertOnShoppingCart($product, $checkoutCart); + $this->countPrices($product, $checkoutCart); + \PHPUnit_Framework_Assert::assertEquals( + $this->fixtureActualPrice, + $this->formPrice, + 'Product price in shopping cart is not correct.' + ); } /** - * Assert prices on the shopping cart + * Count prices. * * @param FixtureInterface $product * @param CheckoutCart $checkoutCart * @return void + */ + protected function countPrices(FixtureInterface $product, CheckoutCart $checkoutCart) + { + /** @var CatalogProductSimple $product */ + $this->fixturePrice = $product->getPrice(); + $this->prepareFormPrice($product, $checkoutCart); + $this->countSpecialPrice($product); + $this->countCheckoutCartItemPrice($product); + $this->countCustomOptionsPrice($product); + } + + /** + * Count count special price. * - * @SuppressWarnings(PHPMD.NPathComplexity) + * @param FixtureInterface $product + * @return void */ - protected function assertOnShoppingCart(FixtureInterface $product, CheckoutCart $checkoutCart) + protected function countSpecialPrice(FixtureInterface $product) { - $checkoutCart->open(); /** @var CatalogProductSimple $product */ - $customOptions = $product->getCustomOptions(); - $checkoutData = $product->getCheckoutData(); - $checkoutCartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; - $checkoutCustomOptions = isset($checkoutData['options']['custom_options']) - ? $checkoutData['options']['custom_options'] - : []; - $fixturePrice = $product->getPrice(); $specialPrice = $product->getSpecialPrice(); - $cartItem = $checkoutCart->getCartBlock()->getCartItem($product); - $formPrice = $cartItem->getPrice(); - if ($specialPrice) { - $fixturePrice = $specialPrice; + $this->fixturePrice = $product->getSpecialPrice(); } + } + + /** + * Prepare form price. + * + * @param FixtureInterface $product + * @param CheckoutCart $checkoutCart + * @return void + */ + protected function prepareFormPrice(FixtureInterface $product, CheckoutCart $checkoutCart) + { + $checkoutCart->open(); + $cartItem = $checkoutCart->getCartBlock()->getCartItem($product); + $this->formPrice = $cartItem->getPrice(); + } + + /** + * Count cart item price. + * + * @param FixtureInterface $product + * @return void + */ + protected function countCheckoutCartItemPrice(FixtureInterface $product) + { + /** @var CatalogProductSimple $product */ + $checkoutData = $product->getCheckoutData(); + $checkoutCartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; if (isset($checkoutCartItem['price'])) { - $fixturePrice = $checkoutCartItem['price']; + $this->fixturePrice = $checkoutCartItem['price']; } - $fixtureActualPrice = $fixturePrice; + $this->fixtureActualPrice = $this->fixturePrice; + } + /** + * Count custom options price. + * + * @param FixtureInterface $product + * @return void + */ + protected function countCustomOptionsPrice(FixtureInterface $product) + { + /** @var CatalogProductSimple $product */ + $customOptions = $product->getCustomOptions(); + $checkoutData = $product->getCheckoutData(); + $checkoutCustomOptions = isset($checkoutData['options']['custom_options']) + ? $checkoutData['options']['custom_options'] + : []; foreach ($checkoutCustomOptions as $checkoutOption) { $attributeKey = str_replace('attribute_key_', '', $checkoutOption['title']); $optionKey = str_replace('option_key_', '', $checkoutOption['value']); $option = $customOptions[$attributeKey]['options'][$optionKey]; if ('Fixed' == $option['price_type']) { - $fixtureActualPrice += $option['price']; + $this->fixtureActualPrice += $option['price']; } else { - $fixtureActualPrice += ($fixturePrice / 100) * $option['price']; + $this->fixtureActualPrice += ($this->fixturePrice / 100) * $option['price']; } } - - \PHPUnit_Framework_Assert::assertEquals( - $fixtureActualPrice, - $formPrice, - 'Product price in shopping cart is not correct.' - ); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php index 74dd831d2df78..5c35c369c1667 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php @@ -1,6 +1,6 @@ getDataFieldConfig('category_ids')['source']->getCategories()[0]; + $storeGroup = $store->getDataFieldConfig('group_id')['source']->getStoreGroup(); + $website = $storeGroup->getDataFieldConfig('website_id')['source']->getWebsite(); + $browser->open( + $_ENV['app_frontend_url'] . 'websites/' . $website->getCode() . '/' . $category->getUrlKey() . '.html' + ); + + $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); + while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { + $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); + } + + \PHPUnit_Framework_Assert::assertTrue( + $isProductVisible, + 'Product is absent on the category page.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product is present on the category page on the custom website.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCustomStoreView.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCustomStoreView.php new file mode 100644 index 0000000000000..8e7f84c27b977 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCustomStoreView.php @@ -0,0 +1,116 @@ +browser = $browser; + $this->cmsIndexPage = $cmsIndexPage; + $this->productViewPage = $catalogProductView; + + $this->verifyProductOnMainStore($initialProduct); + $this->verifyProductOnCustomStore($product, $store); + } + + /** + * Verify product name in default store view. + * + * @param FixtureInterface $initialProduct + * @return void + */ + protected function verifyProductOnMainStore(FixtureInterface $initialProduct) + { + $this->browser->open($_ENV['app_frontend_url'] . $initialProduct->getUrlKey() . '.html'); + + \PHPUnit_Framework_Assert::assertEquals( + $initialProduct->getName(), + $this->productViewPage->getViewBlock()->getProductName(), + 'Product ' . $initialProduct->getName() . ' is incorrect.' + ); + } + + /** + * Verify product name in custom store view. + * + * @param FixtureInterface $updatedProduct + * @param Store $store + * @return void + */ + protected function verifyProductOnCustomStore(FixtureInterface $updatedProduct, Store $store) + { + $this->cmsIndexPage->getStoreSwitcherBlock()->selectStoreView($store->getName()); + $this->cmsIndexPage->getLinksBlock()->waitWelcomeMessage(); + + $this->browser->open($_ENV['app_frontend_url'] . $updatedProduct->getUrlKey() . '.html'); + + \PHPUnit_Framework_Assert::assertEquals( + $updatedProduct->getName(), + $this->productViewPage->getViewBlock()->getProductName(), + 'Product ' . $updatedProduct->getName() . ' is not available on ' . $store->getName() . ' store.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product is displayed correctly in default and custom store views.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php index 8de2d294e1a11..bc186c8e2306e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php @@ -1,6 +1,6 @@ open()->getCartBlock()->clearShoppingCart(); + + $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $catalogProductView->getViewBlock()->waitLoader(); + $catalogProductView->getViewBlock()->setQtyAndClickAddToCart($maxQty * 2); + \PHPUnit_Framework_Assert::assertEquals( + $catalogProductView->getMessagesBlock()->getErrorMessage(), + sprintf($this->errorMessage, $maxQty), + 'The maximum purchase warning message is not appears.' + ); + + $catalogProductView->getViewBlock()->setQtyAndClickAddToCart($maxQty); + \PHPUnit_Framework_Assert::assertTrue( + $catalogProductView->getMessagesBlock()->waitSuccessMessage(), + 'Limiting max qty is not working correctly.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Limiting max qty is working correctly.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMinAllowedQty.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMinAllowedQty.php new file mode 100644 index 0000000000000..aa5aeff49d0b7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMinAllowedQty.php @@ -0,0 +1,72 @@ +open()->getCartBlock()->clearShoppingCart(); + + $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $catalogProductView->getViewBlock()->waitLoader(); + $catalogProductView->getViewBlock()->setQtyAndClickAddToCart(1); + \PHPUnit_Framework_Assert::assertEquals( + $catalogProductView->getMessagesBlock()->getErrorMessage(), + sprintf($this->errorMessage, $minQty), + 'The minimum purchase warning message is not appears.' + ); + + $catalogProductView->getViewBlock()->setQtyAndClickAddToCart($minQty); + \PHPUnit_Framework_Assert::assertTrue( + $catalogProductView->getMessagesBlock()->waitSuccessMessage(), + 'Limiting min qty is not working correctly.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Limiting min qty is working correctly.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryThreshold.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryThreshold.php new file mode 100644 index 0000000000000..dda7d4705b9df --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryThreshold.php @@ -0,0 +1,96 @@ +buyProduct($fixtureFactory, $product, $thresholdItem['qty']); + $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $isThresholdMessageDisplayed = $catalogProductView->getViewBlock() + ->isThresholdMessageDisplayed($browser, $product); + \PHPUnit_Framework_Assert::assertEquals( + $isThresholdMessageDisplayed, + $thresholdItem['is_message_displayed'], + 'Product inventory threshold message display is not correct.' + ); + if ($thresholdItem['is_message_displayed']) { + \PHPUnit_Framework_Assert::assertEquals( + sprintf(self::SUCCESS_MESSAGE, $thresholdItem['expected']), + $catalogProductView->getViewBlock()->getThresholdMessage(), + 'Product inventory success message is not displayed.' + ); + } + } + } + + /** + * Creates an order with product. + * + * @param FixtureFactory $fixtureFactory + * @param FixtureInterface $product + * @param int $qty + * @return void + */ + private function buyProduct(FixtureFactory $fixtureFactory, FixtureInterface $product, $qty) + { + $newProduct = $fixtureFactory->createByCode( + 'catalogProductSimple', + ['data' => ['sku' => $product->getSku(), 'checkout_data' => ['qty' => $qty]]] + ); + $order = $fixtureFactory->createByCode('orderInjectable', [ + 'dataset' => 'guest', + 'data' => [ + 'entity_id' => [ + 'products' => [$newProduct] + ] + ] + ]); + $order->persist(); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product inventory threshold message display is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php index 91ec5026536e3..0d55b90ae4f20 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php @@ -1,6 +1,6 @@ open($_ENV['app_frontend_url'] . $initialProduct->getUrlKey() . '.html'); + foreach ($stores as $store) { + $cmsIndex->getStoreSwitcherBlock()->selectStoreView($store->getName()); + $cmsIndex->getLinksBlock()->waitWelcomeMessage(); + \PHPUnit_Framework_Assert::assertEquals( + $productNames[$store->getStoreId()], + $catalogProductView->getViewBlock()->getProductName(), + sprintf('Wrong product name is displayed for %s store view.', $store->getName()) + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product name is correct on the storefront'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php index f85b18013c998..7ca313f2ccac9 100755 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php @@ -1,6 +1,6 @@ open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); $this->product = $product; + $this->pageView = $catalogProductView; $this->productView = $catalogProductView->getViewBlock(); $errors = $this->verify(); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPriceOnDifferentStoreViews.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPriceOnDifferentStoreViews.php new file mode 100644 index 0000000000000..6c3f9097d083e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPriceOnDifferentStoreViews.php @@ -0,0 +1,58 @@ +open($_ENV['app_frontend_url'] . $initialProduct->getUrlKey() . '.html'); + foreach ($stores as $store) { + $cmsIndex->getStoreSwitcherBlock()->selectStoreView($store->getName()); + $cmsIndex->getLinksBlock()->waitWelcomeMessage(); + \PHPUnit_Framework_Assert::assertEquals( + '9.99', + $catalogProductView->getViewBlock()->getPriceBlock()->getPrice(), + sprintf('Wrong product price is displayed for %s store view.', $store->getName()) + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product name is correct on the storefront'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php index cb3db6bd63488..772bfff4e4a88 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php @@ -1,6 +1,6 @@ open(); + $checkoutCart->getCartBlock()->clearShoppingCart(); + // Add product to cart + $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $requiredQty = $product->getDataFieldConfig('tier_price')['source']->getData()[0]['price_qty']; + $catalogProductView->getViewBlock()->setQtyAndClickAddToCart($requiredQty); + $catalogProductView->getMessagesBlock()->waitSuccessMessage(); + + // Check price + $this->countPrices($product, $checkoutCart); + \PHPUnit_Framework_Assert::assertEquals( + $this->fixtureActualPrice, + $this->formPrice, + 'Product price in shopping cart is not correct.' + ); + } + + /** + * Count prices. + * + * @param FixtureInterface $product + * @param CheckoutCart $checkoutCart + * @return void + */ + private function countPrices(FixtureInterface $product, CheckoutCart $checkoutCart) + { + /** @var CatalogProductSimple $product */ + $this->fixturePrice = $product->getPrice(); + $this->prepareFormPrice($product, $checkoutCart); + $this->countCheckoutCartItemPrice($product); + } + + /** + * Prepare form price. + * + * @param FixtureInterface $product + * @param CheckoutCart $checkoutCart + * @return void + */ + private function prepareFormPrice(FixtureInterface $product, CheckoutCart $checkoutCart) + { + $checkoutCart->open(); + $cartItem = $checkoutCart->getCartBlock()->getCartItem($product); + $this->formPrice = $cartItem->getPrice(); + } + + /** + * Count cart item price. + * + * @param FixtureInterface $product + * @return void + */ + private function countCheckoutCartItemPrice(FixtureInterface $product) + { + $tierPrice = $product->getDataFieldConfig('tier_price')['source']->getData()[0]; + + if ($tierPrice['value_type'] === "Discount") { + $this->fixtureActualPrice = $this->fixturePrice * (1 - $tierPrice['percentage_value'] / 100); + } else { + $this->fixtureActualPrice = $tierPrice['price']; + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product is correctly displayed in cart.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php index 2e40dd98c11fb..c78672a6630f9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php @@ -1,6 +1,6 @@ processAssert($catalogProductView, $browser, $product); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'In stock control is visible for each product.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsOutOfStock.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsOutOfStock.php index 1d6bbeb7fecd9..23a4e5f430dc8 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsOutOfStock.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsOutOfStock.php @@ -1,6 +1,6 @@ open(['id' => $products[$i]->getId()]); + $productData = $catalogProductEdit->getProductForm()->getData($products[$i]); + + $expectedQtyAndStockStatus = [ + 'qty' => $expectedQty[$i], + 'stock_status' => $expectedStockStatus[$i] + ]; + + $actualQtyAndStockStatus['qty'] = $productData['quantity_and_stock_status']['qty']; + $actualQtyAndStockStatus['stock_status'] = + strtolower($productData['quantity_and_stock_status']['is_in_stock']); + + \PHPUnit_Framework_Assert::assertEquals( + $actualQtyAndStockStatus, + $expectedQtyAndStockStatus, + 'Expected and actual products qty and status are not equal.' + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Expected and actual products qty and status are equal.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php index 086a7349b0407..fbc113b7545f9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php @@ -1,6 +1,6 @@ getCheckoutData(); + $this->product = $product; + } + + /** + * Return prepared dataset. + * + * @param null|string $key + * @return array + */ + public function getData($key = null) + { + $checkoutData = $this->product->getCheckoutData(); $cartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; - $customOptions = $product->hasData('custom_options') ? $product->getCustomOptions() : []; + $customOptions = $this->product->hasData('custom_options') ? $this->product->getCustomOptions() : []; $checkoutCustomOptions = isset($checkoutData['options']['custom_options']) ? $checkoutData['options']['custom_options'] : []; @@ -52,9 +67,12 @@ public function __construct(FixtureInterface $product) ? $cartItem['options'] + $checkoutCustomOptions : $checkoutCustomOptions; $cartItem['qty'] = isset($checkoutData['qty']) - ? $checkoutData['qty'] - : 1; - + ? $checkoutData['qty'] + : 1; + $cartItem['sku'] = $this->product->getSku(); + $cartItem['name'] = $this->product->getName(); $this->data = $cartItem; + + return parent::getData($key); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet.xml index a5a20268363bd..23031a762c2b5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet/AssignedAttributes.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet/AssignedAttributes.php index 06c90bee07dca..6be303ddb20f1 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet/AssignedAttributes.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogAttributeSet/AssignedAttributes.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml index b4514208a5093..ab638d09c74da 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple.xml @@ -1,7 +1,7 @@ @@ -36,8 +36,8 @@ - - + + @@ -47,6 +47,8 @@ + + @@ -67,9 +69,11 @@ + + @@ -87,5 +91,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/CustomAttribute.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/CustomAttribute.php index 123fff34f425a..26858313da783 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/CustomAttribute.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/CustomAttribute.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml index b9ba495535e82..e35932a2c5ae4 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category.xml @@ -1,7 +1,7 @@ @@ -20,7 +20,7 @@ - + @@ -41,6 +41,7 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/CategoryProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/CategoryProducts.php index aa3f2138fbe41..91f77c0a85e00 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/CategoryProducts.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/CategoryProducts.php @@ -1,6 +1,6 @@ createByCode($explodeValue[0], ['dataset' => $explodeValue[1]]); - if (!$product->getId()) { - $product->persist(); - } - $this->data[] = $product->getName(); + list($fixtureCode, $dataset) = explode('::', $value); + $this->products[] = $fixtureFactory->createByCode($fixtureCode, ['dataset' => $dataset]); + } + } + if (isset($data['products'])) { + foreach ($data['products'] as $product) { $this->products[] = $product; } } + foreach ($this->products as $product) { + if (!$product->hasData('id')) { + $product->persist(); + } + $this->data[] = $product->getName(); + } } - /** + /**\ * Return products. * * @return array diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/LandingPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/LandingPage.php index 5c50278d16297..fb37fccf2745c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/LandingPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Category/LandingPage.php @@ -1,6 +1,6 @@ data[] = ''; - continue; - } - $category = $fixtureFactory->createByCode('category', ['dataset' => $dataset]); + $category = $fixtureFactory->createByCode('category', ['dataset' => trim($dataset)]); if (!isset($data['new_category']) || $data['new_category'] !== 'yes') { $category->persist(); } @@ -64,6 +60,16 @@ public function __construct( $this->data[] = $category->getName(); $this->categories[] = $category; } + } else { + foreach ($data as $category) { + if ($category instanceof Category) { + if (!$category->hasData('id')) { + $category->persist(); + } + $this->data[] = $category->getName(); + $this->categories[] = $category; + } + } } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/CustomOptions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/CustomOptions.php index 77fcdd5cc083c..7ccf6b3fe515b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/CustomOptions.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/CustomOptions.php @@ -1,6 +1,6 @@ fixtureFactory = $fixtureFactory; + $this->params = $params; + $this->fixtureData = $data; + } + + /** + * {@inheritdoc} + * @throws \Exception + */ + public function getData($key = null) + { + foreach ($this->fixtureData as &$imageData) { + if (isset($imageData['file']) && file_exists(MTF_TESTS_PATH . $imageData['file'])) { + $imageData['file'] = MTF_TESTS_PATH . $imageData['file']; + } else { + throw new \Exception("Image '{$imageData['file']}'' not found on the server."); + } + } + $this->data = $this->fixtureData; + + return parent::getData($key); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/Price.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/Price.php index 00c966c1ca809..6979b38e2307e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/Price.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/Price.php @@ -1,6 +1,6 @@ fixtureData as $dataset) { - if (isset($dataset['dataset'])) { - $store = $this->fixtureFactory->createByCode('store', $dataset); - - if (!$store->getStoreId()) { - $store->persist(); + if (is_array($dataset) && isset($dataset['websites'])) { + foreach ($dataset['websites'] as $website) { + $this->websites[] = $website; } - - $website = $store->getDataFieldConfig('group_id')['source'] - ->getStoreGroup()->getDataFieldConfig('website_id')['source']->getWebsite(); - - $this->data[] = $website->getName(); - $this->websites[] = $website; - $this->stores[] = $store; + } else { + $this->createStore($dataset); } } return parent::getData($key); } + /** + * Create store. + * + * @param array|object $dataset + * @return void + */ + private function createStore($dataset) + { + if ($dataset instanceof Store) { + $store = $dataset; + } elseif (is_array($dataset)) { + $store = isset($dataset['store']) ? $dataset['store'] : + (isset($dataset['dataset']) ? $this->fixtureFactory->createByCode('store', $dataset) : null); + } + if (isset($store)) { + $this->setWebsiteStoreData($store); + } + } + + /** + * Set website and store data. + * + * @param Store $store + * @return void + */ + private function setWebsiteStoreData(Store $store) + { + if (!$store->getStoreId()) { + $store->persist(); + } + $website = $store->getDataFieldConfig('group_id')['source'] + ->getStoreGroup()->getDataFieldConfig('website_id')['source']->getWebsite(); + $this->data[] = $website->getName(); + $this->websites[] = $website; + $this->stores[] = $store; + } + /** * Return stores. * diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogAttributeSet/CatalogAttributeSetInterface.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogAttributeSet/CatalogAttributeSetInterface.php index 5ffe91318fac9..3fe377ebbc564 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogAttributeSet/CatalogAttributeSetInterface.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogAttributeSet/CatalogAttributeSetInterface.php @@ -1,6 +1,6 @@ 0, 'Yes' => 1, ], + 'is_global' => [ + 'Store View' => '0', + 'Global' => '1', + ], + 'used_in_product_listing' => [ + 'No' => '0', + 'Yes' => '1', + ], ]; /** @@ -76,14 +98,16 @@ public function persist(FixtureInterface $fixture = null) unset($data['options']); } - $url = $_ENV['app_backend_url'] . 'catalog/product_attribute/save/back/edit'; + $data = $this->changeStructureOfTheData($data); + $url = $_ENV['app_backend_url'] . $this->urlActionPath; $curl = new BackendDecorator(new CurlTransport(), $this->_configuration); $curl->write($url, $data); $response = $curl->read(); $curl->close(); if (!strpos($response, 'data-ui-id="messages-message-success"')) { - throw new \Exception("Product Attribute creating by curl handler was not successful! \n" . $response); + $this->_eventManager->dispatchEvent(['curl_failed'], [$response]); + throw new \Exception($this->responseExceptionMessage); } $resultData = []; @@ -104,4 +128,13 @@ public function persist(FixtureInterface $fixture = null) return $resultData; } + + /** + * @param array $data + * @return array + */ + protected function changeStructureOfTheData(array $data) + { + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/CatalogProductSimpleInterface.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/CatalogProductSimpleInterface.php index 77bc6b13139e3..9e9b87ebf3297 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/CatalogProductSimpleInterface.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/CatalogProductSimpleInterface.php @@ -1,6 +1,6 @@ fields['product']['website_ids'])) { foreach ($this->fixture->getDataFieldConfig('website_ids')['source']->getWebsites() as $key => $website) { - $this->fields['product']['website_ids'][$key] = $website->getWebsiteId(); + $this->fields['product']['extension_attributes']['website_ids'][$key] = $website->getWebsiteId(); } } else { $website = \Magento\Mtf\ObjectManagerFactory::getObjectManager() ->create(\Magento\Store\Test\Fixture\Website::class, ['dataset' => 'default']); - $this->fields['product']['website_ids'][] = $website->getWebsiteId(); + $this->fields['product']['extension_attributes']['website_ids'][] = $website->getWebsiteId(); } } @@ -488,7 +488,6 @@ protected function prepareCustomOptionsData() if (!isset($this->fields['product']['custom_options'])) { return; } - $options = []; foreach ($this->fields['product']['custom_options'] as $key => $customOption) { $options[$key] = [ @@ -510,7 +509,7 @@ protected function prepareCustomOptionsData() } $this->fields['product']['options'] = $options; - $this->fields['affect_product_custom_options'] = 1; + $this->fields['product']['affect_product_custom_options'] = 1; unset($this->fields['product']['custom_options']); } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Ui.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Ui.php index b9a97660ac3fd..968f007b1b75d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Ui.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductSimple/Ui.php @@ -1,6 +1,6 @@ prepareData(); $this->convertData(); - //TODO: Change create and assign product to website flow using 1 request after MAGETWO-52812 delivery. - /** @var CatalogProductSimple $fixture */ $url = $_ENV['app_frontend_url'] . 'rest/all/V1/products'; $this->webapiTransport->write($url, $this->fields, CurlInterface::POST); @@ -116,106 +107,34 @@ public function persist(FixtureInterface $fixture = null) throw new \Exception("Product creation by webapi handler was not successful! Response: {$encodedResponse}"); } - $this->assignToWebsites($response); - + $this->updateProduct($fixture); return $this->parseResponse($response); } /** - * Assign appropriate Websites to Product and unset all other. + * Update product info per website. * - * @param array $product + * @param FixtureInterface $fixture * @return void - */ - private function assignToWebsites($product) - { - $this->setWebsites($product); - $this->unsetWebsites($product); - } - - /** - * Get all Websites. - * - * @return array * @throws \Exception */ - private function getAllWebsites() + private function updateProduct(FixtureInterface $fixture) { - $url = $_ENV['app_frontend_url'] . 'rest/V1/store/websites'; - $this->webapiTransport->write($url, [], CurlInterface::GET); - $encodedResponse = $this->webapiTransport->read(); - $response = json_decode($encodedResponse, true); - $this->webapiTransport->close(); - - if (!isset($response[0]['id'])) { - $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); - throw new \Exception( - "Attempt to get all Websites by webapi handler was not successful! Response: {$encodedResponse}" - ); - } - - return $response; - } - - /** - * Set appropriate Websites to Product. - * - * @param array $product - * @return void - * @throws \Exception - */ - private function setWebsites($product) - { - foreach ($this->websiteIds as $id) { - $url = $_ENV['app_frontend_url'] . 'rest/V1/products/' . $product['sku'] . '/websites'; - $productWebsiteLink = ['productWebsiteLink' => ['website_id' => $id, 'sku' => $product['sku']]]; - $this->webapiTransport->write($url, $productWebsiteLink, CurlInterface::POST); - $encodedResponse = $this->webapiTransport->read(); - $response = json_decode($encodedResponse, true); - $this->webapiTransport->close(); - - if ($response !== true) { - $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); - throw new \Exception( - "Product addition to Website by webapi handler was not successful! Response: {$encodedResponse}" - ); - } - } - } - - /** - * Unset all Websites from Product except appropriate. - * - * @param array $product - * @return void - * @throws \Exception - */ - private function unsetWebsites($product) - { - $allWebsites = $this->getAllWebsites(); - $websiteIds = []; - - foreach ($allWebsites as $website) { - if ($website['code'] == 'admin') { - continue; - } - $websiteIds[] = $website['id']; - } - - $websiteIds = array_diff($websiteIds, $this->websiteIds); - - foreach ($websiteIds as $id) { - $url = $_ENV['app_frontend_url'] . 'rest/V1/products/' . $product['sku'] . '/websites/' . $id; - $this->webapiTransport->write($url, [], CurlInterface::DELETE); - $encodedResponse = $this->webapiTransport->read(); - $response = json_decode($encodedResponse, true); - $this->webapiTransport->close(); - - if ($response !== true) { - $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); - throw new \Exception( - "Product deduction from Website by webapi handler was not successful! Response: {$encodedResponse}" - ); + if (isset($fixture->getData()['website_data'])) { + $websiteData = $fixture->getData()['website_data']; + foreach ($fixture->getDataFieldConfig('website_ids')['source']->getStores() as $key => $store) { + $url = $_ENV['app_frontend_url'] . 'rest/' . $store->getCode() . '/V1/products/' . $fixture->getSku(); + $this->webapiTransport->write($url, ['product' => $websiteData[$key]], CurlInterface::PUT); + $encodedResponse = $this->webapiTransport->read(); + $response = json_decode($encodedResponse, true); + $this->webapiTransport->close(); + + if (!isset($response['id'])) { + $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); + throw new \Exception( + "Product update by webapi handler was not successful! Response: {$encodedResponse}" + ); + } } } } @@ -244,7 +163,6 @@ protected function prepareData() protected function convertData() { $fields = []; - $this->websiteIds = $this->fields['product']['website_ids']; unset($this->fields['product']['website_ids']); unset($this->fields['product']['checkout_data']); @@ -347,8 +265,16 @@ protected function prepareTierPrice() $priceInfo['customer_group_id'] = $priceInfo['cust_group']; unset($priceInfo['cust_group']); - $priceInfo['value'] = $priceInfo['price']; - unset($priceInfo['price']); + if (isset($priceInfo['price'])) { + $priceInfo['value'] = $priceInfo['price']; + unset($priceInfo['price']); + } + unset($priceInfo['value_type']); + + if (isset($priceInfo['percentage_value'])) { + $priceInfo['extension_attributes']['percentage_value'] = $priceInfo['percentage_value']; + unset($priceInfo['percentage_value']); + } $priceInfo['qty'] = $priceInfo['price_qty']; unset($priceInfo['price_qty']); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductVirtual/CatalogProductVirtualInterface.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductVirtual/CatalogProductVirtualInterface.php index d00f843548aba..281e2774b15d4 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductVirtual/CatalogProductVirtualInterface.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Handler/CatalogProductVirtual/CatalogProductVirtualInterface.php @@ -1,6 +1,6 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogCategoryIndex.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogCategoryIndex.xml index dc910d03b772b..c4268f1ed9c8d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogCategoryIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogCategoryIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductActionAttributeEdit.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductActionAttributeEdit.xml index e875bdc0817e9..d15076bcf5e8f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductActionAttributeEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductActionAttributeEdit.xml @@ -1,13 +1,13 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeIndex.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeIndex.xml index 3268efba2181f..3653286fad904 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeNew.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeNew.xml index 6e8f3f22a335f..feb29ebc8f304 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeNew.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductAttributeNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml index dc6b1e8213628..0fb0eb1783a13 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductIndex.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductIndex.xml index a1de0d5599564..2982a6070a0ea 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductIndex.xml @@ -1,13 +1,13 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductNew.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductNew.xml index 9d0740aea9382..1a721517203eb 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductNew.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetAdd.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetAdd.xml index fb9677fbb7037..a07b54d15170b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetAdd.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetAdd.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetEdit.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetEdit.xml index 69315ee9c204d..0dad417d33034 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetIndex.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetIndex.xml index 55a1ca7ff1178..df50d6b1ab2b5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Adminhtml/CatalogProductSetIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Category/CatalogCategory.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Category/CatalogCategory.php index cc0d6182a7d9f..999d657eed28e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Category/CatalogCategory.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Category/CatalogCategory.php @@ -1,6 +1,6 @@ @@ -15,5 +15,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml index d61e8e78466e0..21e00ff6b0627 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/CmsIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductCompare.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductCompare.xml index bea68dbe49b63..f107a13ce1a8d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductCompare.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductCompare.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductView.xml index 6c4ac6bacbe42..ba82c60f24ee0 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml index a62bef0680a9e..7fdf9d3b03672 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml @@ -1,7 +1,7 @@ @@ -38,5 +38,15 @@ color_for_promo_rules + + + Custom_attribute_set_with_sizes_%isolation% + + default + + + sizes_for_promo_rules + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml index e94af12754af5..55efc1f4f6b3a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml @@ -1,7 +1,7 @@ @@ -204,5 +204,55 @@ + + + size_%isolation% + size_%isolation% + Dropdown + No + + + No + SIZE_S + SIZE_S + + + No + SIZE_M + SIZE_M + + + No + SIZE_L + SIZE_L + + + + + + size_%isolation% + size_%isolation% + Dropdown + Yes + No + + + Yes + SIZE_S_%isolation% + SIZE_S + + + No + SIZE_M_%isolation% + SIZE_M + + + No + SIZE_L_%isolation% + SIZE_L + Yes + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute/Options.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute/Options.xml index eb6585cf8c9e0..f1d862a9c7d1d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute/Options.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute/Options.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml index 23c13fb1206df..7dd87a8abe76f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml @@ -1,7 +1,7 @@ @@ -68,6 +68,37 @@ + + + default + + Product with long name %isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation%%isolation% + sku_simple_product_%isolation% + No + This item has weight + 1 + + 25 + In Stock + + + 560 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + Simple Product %isolation% simple_product_%isolation% @@ -98,6 +129,87 @@ simple-product-%isolation% + + + default + + product_1_dollar %isolation% + sku_product_1_dollar_%isolation% + This item has weight + 1 + + 1000 + In Stock + + + 1 + + + taxable_goods + + + + default + + + Catalog, Search + product-1-dollar-%isolation% + + + + + default + + product_5_dollar %isolation% + sku_product_5_dollar_%isolation% + This item has weight + 1 + + 1000 + In Stock + + + 5 + + + taxable_goods + + + + default + + + Catalog, Search + product-5-dollar-%isolation% + + + + + default + + product_9_99_dollar %isolation% + sku_product_9_99_dollar_%isolation% + This item has weight + 1 + + 1000 + In Stock + + + 9.99 + + + taxable_goods + + + + default + + + Catalog, Search + product-9-99-dollar-%isolation% + + default @@ -128,6 +240,33 @@ + + + default + + product_15_dollar %isolation% + sku_product_15_dollar_%isolation% + This item has weight + 1 + + 1000 + In Stock + + + 15 + + + taxable_goods + + + + default + + + Catalog, Search + product-15-dollar-%isolation% + + default @@ -155,6 +294,60 @@ product-20-dollar-%isolation% + + + default + + product_30_dollar %isolation% + sku_product_30_dollar_%isolation% + This item has weight + 1 + + 1000 + In Stock + + + 30 + + + taxable_goods + + + + default + + + Catalog, Search + product-30-dollar-%isolation% + + + + + default + + product_21_dollar %isolation% + sku_product_21_dollar_%isolation% + This item has weight + 1 + + 1000 + In Stock + + + 21 + + + taxable_goods + + + + default + + + Catalog, Search + product-21-dollar-%isolation% + + Simple Product %isolation% sku_simple_product_%isolation% @@ -1172,6 +1365,39 @@ + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + simple-product-%isolation% + This item has weight + 1 + + 1 + In Stock + + + 10 + + + taxable_goods + + + + default + + + Catalog, Search + + simple_order_default + + + default_subcategory + + + default @@ -1215,7 +1441,9 @@ taxable_goods - Main Website + + default + Catalog, Search simple-product-%isolation% @@ -1231,5 +1459,435 @@ overnight-duffle + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + + 56.78 + + This item has weight + 1 + + 1 + In Stock + + + + default + + + simple-product-%isolation% + + default_subcategory + + + percent_and_fixed_radio_options + + + with_fixed_custom_option + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + + 100 + + This item has weight + 1 + + 1 + In Stock + + + + default + + + simple-product-%isolation% + + default_subcategory + + + text_and_two_custom_options + + + text_and_two_custom_options + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + + 56.78 + + This item has weight + 1 + + 1 + In Stock + + + + default + + + simple-product-%isolation% + + default_subcategory + + + percent_and_fixed_radio_options + + + with_percent_custom_option + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 1 + + 25 + In Stock + + + 20.01 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 1 + + 25 + In Stock + + + 79.99 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 10 + + 25 + In Stock + + + 560 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 2 + + 25 + In Stock + + + 560 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + + 56.78 + + This item has weight + 1 + + 1 + In Stock + + + + default + + + simple-product-%isolation% + + default_subcategory + + + percent_and_fixed_radio_options + + + simple_order_qty_1_price_56 + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 1 + + 3 + In Stock + + + 560 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 1 + + 1 + In Stock + + + 560 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 1 + + 2 + In Stock + + + 560 + + + taxable_goods + + + + default + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + + default + + Simple Product %isolation% + sku_simple_product_%isolation% + This item has weight + 1 + + 25 + In Stock + + + 560 + + + taxable_goods + + + + custom_store + + + Catalog, Search + simple-product-%isolation% + + simple_order_default + + + + + simple_product_with_category_%isolation% + Simple product with category %isolation% + + 777 + In Stock + + This item has weight + 1 + + default + + + 10 + + + + default_subcategory + + + + default + + + custom_store + + + simple-product-%isolation% + + + + simple_product_with_category_%isolation% + Simple product with category %isolation% + + 777 + In Stock + + This item has weight + 1 + + default + + + 10 + + + + default_subcategory + + + + default + + + custom_store + + + simple-product-%isolation% + + custom_price_in_main_and_custom_websites + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml index 53ec00f56b1e8..b9f419d3c87bd 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/CheckoutData.xml @@ -1,7 +1,7 @@ @@ -28,6 +28,27 @@ + + + + + attribute_key_0 + option_key_1 + + + attribute_key_1 + Content option %isolation% + + + + 2 + + 370 + 1 + 740 + + + @@ -101,6 +122,14 @@ + + 2 + + 560 + 560 + + + 2 @@ -129,6 +158,14 @@ + + 5 + + 40 + 40 + + + 1 @@ -148,5 +185,85 @@ 3 + + + + + + attribute_key_0 + option_key_0 + + + + 1 + + 560.78 + 1 + 560.78 + + + + + + + + attribute_key_0 + Ok + + + attribute_key_1 + option_key_0 + + + + 1 + + 5 + 1 + 125 + + + + + 1 + + 49.40 + 49.40 + + + + + + + + attribute_key_0 + option_key_0 + + + + 1 + + 61.74 + 1 + 61.74 + + + + + + + + attribute_key_0 + option_key_1 + + + + 1 + + 53.85 + 1 + 53.85 + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/Price.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/Price.xml index 35a33fe591a79..8480764792bb3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/Price.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/Price.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/WebsiteData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/WebsiteData.xml new file mode 100644 index 0000000000000..b2c891d7a9ab8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple/WebsiteData.xml @@ -0,0 +1,19 @@ + + + + + + + 15 + + + 20 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml index 7f56333969a0d..9f0c91047b473 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual.xml @@ -1,7 +1,7 @@ @@ -75,6 +75,36 @@ + + + taxable_goods + + Yes + + + default + + + virtual-product%isolation% + Catalog, Search + + default + + Virtual product %isolation% + sku_virtual_product_%isolation% + + 1 + In Stock + + This item has no weight + + 10 + + + virtual_order_default + + + taxable_goods @@ -188,5 +218,35 @@ virtual_order_default + + + + taxable_goods + + Yes + + + default + + + virtual-product%isolation% + Catalog, Search + + default + + Virtual product %isolation% + sku_virtual_product_%isolation% + + 1 + In Stock + + This item has no weight + + 10 + + + virtual_order_default + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual/CheckoutData.xml index 026b32c021980..a1464257ca1dc 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductVirtual/CheckoutData.xml @@ -1,7 +1,7 @@ @@ -34,6 +34,11 @@ 2 + + 10 + 2 + 20 + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml index 30f870dea88f0..f0fdb5a76a262 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml @@ -1,7 +1,7 @@ @@ -25,7 +25,6 @@ - %id% DefaultSubcategory%isolation% default-subcategory-%isolation% @@ -35,6 +34,15 @@ Yes + + DefaultSubcategory%isolation% + + default_category + + Yes + Yes + + DefaultSubcategory%isolation% default-subcategory-%isolation% @@ -67,10 +75,53 @@ Category%isolation% category-%isolation% - default_subcategory + default + + Yes + Yes + + + + Category%isolation% + category-%isolation% + + two_nested_categories Yes Yes + + + Category%isolation% + category-%isolation% + + three_nested_categories + + Yes + Yes + + + + Category%isolation% + category-%isolation% + + four_nested_categories + + Yes + Yes + + + + Category%isolation% + category%isolation% + Yes + Yes + + default_category + + + catalogProductSimple::default + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml index 0b3452cc14782..f8ae8b0776d7f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -23,5 +23,76 @@ 0 + + + + + + + + {{name}} + 1 + + + + + {{name}} {{country_of_manufacture}} + + + + + {{name}} + 1 + + + + + 5 + + + + + 0 + 1 + + + + + 5 + + + + + 0 + 1 + + + + + 3 + + + + + 0 + 1 + + + + + default + 0 + Website + 1 + + + + + default + 0 + Global + 0 + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml index 2b826e84b8e13..69e0cbcd9b30b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml @@ -1,7 +1,7 @@ @@ -75,6 +75,37 @@ + + + custom option drop down %isolation% + Yes + Select/Drop-down + + + 30 bucks + 30 + Fixed + sku_drop_down_row_1 + 0 + + + + + custom option drop down 2 %isolation% + Yes + Select/Drop-down + + + 40 Percent + 40 + Percent + sku_drop_down_row_1 + 0 + + + + + custom option drop down %isolation% @@ -327,5 +358,137 @@ + + + + custom menu + No + Select/Radio Buttons + + + 12.34 bucks + 12.34 + Fixed + sku_radio_buttons_row_1 + 0 + + + 9 Percent + 9 + Percent + sku_radio_buttons_row_2 + 0 + + + + + + + + 30 bucks + Yes + Text/Field + + + 30 + Fixed + sku_field_option_%isolation% + 1024 + + + + + custom menu + Yes + Select/Radio Buttons + + + 5 bucks + 5 + Fixed + sku_radio_buttons_row_1 + 0 + + + 10 bucks + 10 + Fixed + sku_radio_buttons_row_2 + 1 + + + + + + + + custom menu + No + Select/Radio Buttons + + + 12 bucks + 12 + Fixed + sku_radio_buttons_row_1 + 0 + + + 89 bucks + 89 + Fixed + sku_radio_buttons_row_2 + 0 + + + + + + + + custom option drop down %isolation% + Yes + Select/Drop-down + + + 12 bucks + 12 + Fixed + sku_radio_buttons_row_1 + 0 + + + 12 bucks + 12 + Fixed + sku_radio_buttons_row_1 + 0 + + + 12 bucks + 12 + Fixed + sku_radio_buttons_row_1 + 0 + + + + + + + + Test1 option %isolation% + No + Text/Field + + + 10 + Fixed + sku1_%isolation% + 45 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/Fpt.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/Fpt.xml index d45a889fb5d6b..f9386e33d8d7e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/Fpt.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/Fpt.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml index bdfb5deabe5c2..a6fa18347910a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml @@ -1,7 +1,7 @@ @@ -66,5 +66,40 @@ + + + + 90 + All Websites [USD] + 2 + + NOT_LOGGED_IN + + + + + + + Fixed + 95 + All Websites [USD] + 5 + + ALL_GROUPS + + + + + + + Discount + 3 + All Websites [USD] + 10 + + ALL_GROUPS + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.php index d458ffeb22475..a4cbd8f3a84cd 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.php @@ -1,6 +1,6 @@ @@ -16,6 +16,7 @@ + MAGETWO-60635: [CE][Categories] Design update dates are incorrect after save Create root category with all fields addRootCategory Yes @@ -39,8 +40,8 @@ <referenceContainer name="catalog.leftnav" remove="true"/> Magento Luma Yes - Jan 10, 2014 - Dec 31, 2024 + 01/10/2014 + 12/31/2024 @@ -56,6 +57,7 @@ + MAGETWO-60635: [CE][Categories] Design update dates are incorrect after save Create not anchor subcategory specifying all fields addSubcategory default_category @@ -82,9 +84,12 @@ <referenceContainer name="content.aside" remove="true"/> Magento Luma Yes - Jan 1, 2014 - Dec 31, 2024 + 01/10/2014 + 12/31/2024 + request_path + No + @@ -149,11 +154,10 @@ - + test_type:extended_acceptance_test - Create category with three nesting addSubcategory - two_nested_categories + five_nested_categories Yes Category%isolation% Category Required @@ -162,5 +166,14 @@ + + addSubcategory + root_category + Yes + Yes + Subcategory%isolation% + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/DeleteCategoryEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/DeleteCategoryEntityTest.php index e7b613f43af59..ac1415f51c5cb 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/DeleteCategoryEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/DeleteCategoryEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/MoveCategoryEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/MoveCategoryEntityTest.php new file mode 100644 index 0000000000000..1420487598f0d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/MoveCategoryEntityTest.php @@ -0,0 +1,92 @@ +Inventory>Categories + * 3. Click on 'Add Category' button + * 4. Fill out all data according to data set + * 5. Save category + * 6. Verify created category + * + * @group Category_Management + * @ZephyrId MAGETWO-27319 + */ +class MoveCategoryEntityTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + /* end tags */ + + /** + * CatalogCategoryIndex page. + * + * @var CatalogCategoryIndex + */ + private $catalogCategoryIndex; + + /** + * CatalogCategoryEdit page. + * + * @var CatalogCategoryEdit + */ + private $catalogCategoryEdit; + + /** + * Inject page end prepare default category. + * + * @param CatalogCategoryIndex $catalogCategoryIndex + * @param CatalogCategoryEdit $catalogCategoryEdit + * @return void + */ + public function __inject( + CatalogCategoryIndex $catalogCategoryIndex, + CatalogCategoryEdit $catalogCategoryEdit + ) { + $this->catalogCategoryIndex = $catalogCategoryIndex; + $this->catalogCategoryEdit = $catalogCategoryEdit; + } + + /** + * Runs test. + * + * @param Category $childCategory + * @param Category $parentCategory + * @return array + */ + public function test(Category $childCategory, Category $parentCategory) + { + // Preconditions: + $parentCategory->persist(); + $childCategory->persist(); + + // Steps: + $this->catalogCategoryIndex->open(); + $this->catalogCategoryIndex->getTreeCategories()->expandAllCategories(); + $this->catalogCategoryIndex->getTreeCategories()->assignCategory( + $parentCategory->getName(), + $childCategory->getName() + ); + $this->catalogCategoryEdit->getModalBlock()->acceptWarning(); + + return [ + 'category' => $childCategory, + 'parentCategory' => $parentCategory, + 'childCategory' => $childCategory + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/MoveCategoryEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/MoveCategoryEntityTest.xml new file mode 100644 index 0000000000000..28bb3799c5c2b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/MoveCategoryEntityTest.xml @@ -0,0 +1,18 @@ + + + + + + three_nested_categories + default + 3 + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php index ab8b03e8bfe15..0595993bc3dba 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.php @@ -1,6 +1,6 @@ catalogCategoryIndex->getTreeCategories()->selectCategory($initialCategory); $this->catalogCategoryEdit->getEditForm()->fill($category); $this->catalogCategoryEdit->getFormPageActions()->save(); - return ['category' => $this->prepareCategory($category, $initialCategory)]; } @@ -109,11 +108,16 @@ protected function prepareCategory(Category $category, Category $initialCategory ? $category->getDataFieldConfig('parent_id')['source']->getParentCategory() : $initialCategory->getDataFieldConfig('parent_id')['source']->getParentCategory(); + $rewriteData = ['parent_id' => ['source' => $parentCategory]]; + if ($category->hasData('store_id')) { + $rewriteData['store_id'] = ['source' => $category->getDataFieldConfig('store_id')['source']->getStore()]; + } + $data = [ 'data' => array_merge( $initialCategory->getData(), $category->getData(), - ['parent_id' => ['source' => $parentCategory]] + $rewriteData ) ]; diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml index e98cd1529409a..e3f502a68a773 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateCategoryEntityTest.xml @@ -1,7 +1,7 @@ @@ -14,6 +14,7 @@ Category Description Updated UrlKey%isolation% Category Title Updated + No @@ -50,5 +51,13 @@ + + default_category + custom + No + UrlKey%isolation% + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateTopCategoryEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateTopCategoryEntityTest.php new file mode 100644 index 0000000000000..5ca725dd1d282 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateTopCategoryEntityTest.php @@ -0,0 +1,179 @@ +Categories. + * 2. Open category created in preconditions. + * 3. Update data according to data set. + * 4. Save category. + * 5. Perform assertions. + * + * @group Category_Management + * @ZephyrId MAGETWO-27327 + */ +class UpdateTopCategoryEntityTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + /* end tags */ + + /** + * Catalog category index page. + * + * @var CatalogCategoryIndex + */ + protected $catalogCategoryIndex; + + /** + * Catalog category edit page. + * + * @var CatalogCategoryEdit + */ + protected $catalogCategoryEdit; + + /** + * Fixture Factory. + * + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Inject pages. + * + * @param CatalogCategoryIndex $catalogCategoryIndex + * @param CatalogCategoryEdit $catalogCategoryEdit + * @param FixtureFactory $fixtureFactory + * @return void + */ + public function __inject( + CatalogCategoryIndex $catalogCategoryIndex, + CatalogCategoryEdit $catalogCategoryEdit, + FixtureFactory $fixtureFactory + ) { + $this->fixtureFactory = $fixtureFactory; + $this->catalogCategoryIndex = $catalogCategoryIndex; + $this->catalogCategoryEdit = $catalogCategoryEdit; + } + + /** + * Top parent category update test. + * + * @param Category $category + * @param Category $initialCategory + * @param int $nestingLevel + * @return array + */ + public function test( + Category $category, + Category $initialCategory, + $nestingLevel + ) { + $initialCategory->persist(); + $topCategory = $this->getParentCategoryByNestingLevel($initialCategory, $nestingLevel); + $this->catalogCategoryIndex->open(); + $this->catalogCategoryIndex->getTreeCategories()->selectCategory($topCategory); + $this->catalogCategoryEdit->getEditForm()->fill($category); + $this->catalogCategoryEdit->getFormPageActions()->save(); + + $categories = []; + $categoriesBeforeSave = []; + $this->getCategoryFixture($categories, $initialCategory, $category->getData(), $nestingLevel); + $this->getCategory($initialCategory, $categoriesBeforeSave, $nestingLevel); + + return [ + 'categories' => $categories, + 'categoriesBeforeSave' => $categoriesBeforeSave + ]; + } + + /** + * Get category fixture after saving in the admin panel. + * + * @param array $categories + * @param Category $currentCategory + * @param array $data + * @param int $nestingLevel + * @return Category + */ + private function getCategoryFixture(array &$categories, Category $currentCategory, array $data, int $nestingLevel) + { + if (--$nestingLevel) { + $parentCategory = $this->getCategoryFixture( + $categories, + $currentCategory->getDataFieldConfig('parent_id')['source']->getParentCategory(), + $data, + $nestingLevel + ); + $category = $this->fixtureFactory->createByCode( + 'category', + ['data' => array_merge($currentCategory->getData(), ['parent_id' => ['source' => $parentCategory]])] + ); + } else { + $category = $this->fixtureFactory->createByCode( + 'category', + ['data' => array_merge($currentCategory->getData(), $data)] + ); + } + $categories[$nestingLevel + 1] = $category; + return $category; + } + + /** + * Get category before it was saved in the admin panel. + * + * @param Category $initialCategory + * @param array $categoriesBeforeSave + * @param int $nestingLevel + * @return Category + */ + private function getCategory(Category $initialCategory, &$categoriesBeforeSave, $nestingLevel) + { + if (--$nestingLevel) { + $parentCategory = $this->getCategory( + $initialCategory->getDataFieldConfig('parent_id')['source']->getParentCategory(), + $categoriesBeforeSave, + $nestingLevel + ); + $category = $this->fixtureFactory->createByCode( + 'category', + ['data' => array_merge($initialCategory->getData(), ['parent_id' => ['source' => $parentCategory]])] + ); + } else { + $category = $initialCategory; + } + $categoriesBeforeSave[$nestingLevel + 1] = $category; + return $category; + } + + /** + * Get parent category by category nesting level. + * + * @param Category $category + * @param int $nestingLevel + * @return Category + */ + private function getParentCategoryByNestingLevel(Category $category, $nestingLevel) + { + for ($nestingIterator = 1; $nestingIterator < $nestingLevel; $nestingIterator++) { + $category = $category->getDataFieldConfig('parent_id')['source']->getParentCategory(); + } + + return $category; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateTopCategoryEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateTopCategoryEntityTest.xml new file mode 100644 index 0000000000000..16b48b1e12841 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/UpdateTopCategoryEntityTest.xml @@ -0,0 +1,27 @@ + + + + + + three_nested_categories + 3 + cat1-rewrite%isolation% + No + request_path + No + + + + three_nested_categories + 3 + cat1-rewrite%isolation% + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml index 2c8528595f44b..1e6e5d4c5cf26 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ @@ -14,7 +14,7 @@ Products > Categories - Default Category + Default Category (ID: 2) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php index 1c266fd9040dd..1e7115bc93d03 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php @@ -1,6 +1,6 @@ @@ -10,6 +10,7 @@ catalogProductSimple::simple_for_composite_products No + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php index 59f45bc004b82..492d8d9859935 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php @@ -1,6 +1,6 @@ - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, stable:no simple1::catalogProductSimple::product_with_category,simple2::catalogProductSimple::product_with_category,config1::configurableProduct::two_options_with_fixed_price simple1:simple2,config1;config1:simple2 simple1,config1,simple2 diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php index ebc7360fe004b..7c35ec1094d2c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ClearAllCompareProductsTest.php @@ -1,6 +1,6 @@ + stable:no compare_products catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.php new file mode 100644 index 0000000000000..1f2d690773c82 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.php @@ -0,0 +1,134 @@ + Catalog. + * 3. Start to create simple product. + * 4. Fill in data according to data set. + * 5. Save Product. + * 6. Perform appropriate assertions. + * + * @group Products + * @ZephyrId MAGETWO-59861 + */ +class CreateSimpleProductEntityByAttributeMaskSkuTest extends Injectable +{ + /** + * Configuration setting. + * + * @var string + */ + protected $configData; + + /** + * Should cache be flushed + * + * @var bool + */ + private $flushCache; + + /** + * @var \Magento\Mtf\Fixture\FixtureFactory + */ + private $fixtureFactory; + + /** + * Run create product simple entity by attribute mask SKU test. + * + * @param CatalogProductSimple $product + * @param CatalogProductIndex $productGrid + * @param CatalogProductNew $newProductPage + * @param string $configData + * @param bool $flushCache + * @return array + */ + public function testCreate( + CatalogProductSimple $product, + CatalogProductIndex $productGrid, + CatalogProductNew $newProductPage, + \Magento\Mtf\Fixture\FixtureFactory $fixtureFactory, + $flushCache = false, + $configData = null + ) { + $this->configData = $configData; + $this->flushCache = $flushCache; + $this->fixtureFactory = $fixtureFactory; + + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'flushCache' => $this->flushCache] + )->run(); + + // Steps + $productGrid->open(); + $productGrid->getGridPageActionBlock()->addProduct('simple'); + $newProductPage->getProductForm()->fill($product); + $newProductPage->getFormPageActions()->save(); + + $skuMask = $this->prepareSkuByMask($product); + + $productSimple = $fixtureFactory->createByCode( + 'catalogProductSimple', + ['data' => array_merge($product->getData(), ['sku' => $skuMask])] + ); + + return ['product' => $productSimple]; + } + + /** + * Obtains product sku based on attributes define in Stores > Configuration->Catalog > Catalog > Mask for SKU + * + * @param CatalogProductSimple $product + * @return string + */ + private function prepareSkuByMask(CatalogProductSimple $product) + { + $productData = $product->getData(); + $skuMask = ''; + $config = $this->fixtureFactory->createByCode('configData', ['dataset' => $this->configData]); + $section = $config->getData('section'); + if (is_array($section) && array_key_exists('catalog/fields_masks/sku', $section)) { + $skuMask = $section['catalog/fields_masks/sku']['value']; + } + + $attributesInPattern = []; + $count = preg_match_all('/{{(\w+)}}/', $skuMask, $matches); + if ($count > 0 && is_array($matches[0])) { + foreach ($matches[1] as $attributeName) { + if (array_key_exists($attributeName, $productData)) { + $attributesInPattern[$attributeName] = $productData[$attributeName]; + } + } + } + foreach ($attributesInPattern as $attributeName => $attributeValue) { + $skuMask = str_replace('{{' . $attributeName . '}}', $attributeValue, $skuMask); + } + return $skuMask; + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true, 'flushCache' => $this->flushCache] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.xml new file mode 100644 index 0000000000000..8ab6a88fe750b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityByAttributeMaskSkuTest.xml @@ -0,0 +1,23 @@ + + + + + + attribute_product_mask_sku + Create product with country of manufacture attribute sku mask + simple-product-%isolation% + Simple Product %isolation% + 10000 + 50 + 657 + Ukraine + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.php index c0cab5ef8e6b7..95a4c337b91a0 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityTest.php @@ -1,6 +1,6 @@ @@ -137,6 +137,7 @@ simple_drop_down_with_one_option_percent_price MAGETWO-23030 MAGETWO-23002 + to_maintain:yes @@ -157,6 +158,7 @@ simple_drop_down_with_one_option_fixed_price MAGETWO-23029 MAGETWO-23002 + to_maintain:yes @@ -168,7 +170,7 @@ simple-product-%isolation% Simple Product %isolation% simple_sku_%isolation% - 10008 + 10008.88 Simple Product short_description %isolation% Simple Product description %isolation% 58 @@ -178,19 +180,29 @@ - - Create product that is in stock + + inventory_threshold_5 simple-product-%isolation% Simple Product %isolation% simple_sku_%isolation% 10009 - Simple Product short_description %isolation% - Simple Product description %isolation% 59 - 75 + 10 In Stock + + + 4 + false + + + 1 + true + 5 + + + Create product that is out stock @@ -206,19 +218,22 @@ - - Create product that visible only in search + + MAGETWO-63217: Error message doesn't appear on add in the cart less products than configured + inventory_min_qty_3, inventory_max_qty_5 simple-product-%isolation% Simple Product %isolation% simple_sku_%isolation% 10011 - Simple Product short_description %isolation% - Simple Product description %isolation% 61 138 Search + 3 + 5 + + Create simple product and check search by sku @@ -255,6 +270,7 @@ + stable:no Create product with tax class and group price simple-product-%isolation% Simple Product %isolation% @@ -303,6 +319,7 @@ 66 143 default + to_maintain:yes @@ -312,6 +329,7 @@ + MAGETWO-60470: [Import Custom options] An error occurs on attempt to save the product with imported options Create product wit suite of custom options simple-product-%isolation% Simple Product %isolation% @@ -324,6 +342,7 @@ options_suite simple_options_suite catalogProductSimple::with_two_custom_option,catalogProductSimple::with_all_custom_option + MAGETWO-58181: All kind of Custom Options have dynamic view on Bamboo @@ -333,6 +352,7 @@ + stable:no simple-product-%isolation% Simple Product %isolation% simple_sku_%isolation% @@ -349,6 +369,7 @@ + stable:no simple-product-%isolation% Simple Product %isolation% simple_sku_%isolation% @@ -393,17 +414,20 @@ - + yes - default_subcategory + default_subcategory_without_url_key + default simple%isolation% simple%isolation% simple%isolation% 10 345 + Temporary (302) + simple-product-%isolation% @@ -461,5 +485,87 @@ Antarctica + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 100 + 50 + 667 + not_logged_in + + + + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 200.20 + 50 + 668 + custom_store + + + + + empty_product_mask_sku + Create product with custom options(fixed price) + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 10000 + 50 + 657 + simple_drop_down_with_one_option_fixed_price + drop_down_with_one_option_fixed_price + + + + + + + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 100.00 + 555 + custom_with_fixed_discount + + + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 200.00 + 555 + custom_with_percentage_discount + + + + Magento/Catalog/Test/_files/test1.png + Magento/Catalog/Test/_files/test2.png + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 10 + 50 + severity:S1 + 100 + + + + + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 15 + 5 + 1 + Not Visible Individually + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.php index 290275ef4e872..3b9c264f9d328 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateVirtualProductEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes Create product with required fields virtual-product-%isolation% VirtualProduct %isolation% @@ -17,7 +18,7 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, to_maintain:yes virtual-product-%isolation% VirtualProduct %isolation% virtual_sku_%isolation% @@ -65,12 +66,14 @@ In Stock Catalog, Search default + to_maintain:yes + to_maintain:yes Create product with custom options suite and import options virtual-product-%isolation% VirtualProduct %isolation% @@ -110,6 +113,7 @@ 999 default Out of Stock + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php index 7026b757bb7de..258dbdde07874 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteCompareProductsTest.php @@ -1,6 +1,6 @@ + stable:no catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product 1 No @@ -15,6 +16,7 @@ + stable:no catalogProductSimple::simple_for_composite_products,catalogProductVirtual::default,downloadableProduct::default,groupedProduct::grouped_product_with_price,configurableProduct::default,bundleProduct::bundle_dynamic_product,bundleProduct::bundle_fixed_product 6 Yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteProductEntityTest.php index 1a0c46b146faf..4ea54f6321113 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DeleteProductEntityTest.php @@ -1,6 +1,6 @@ @@ -10,6 +10,7 @@ catalogProductSimple::default Yes + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DuplicateProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DuplicateProductEntityTest.php index bdf90b5df3bc5..e0db7c27bea6b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DuplicateProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/DuplicateProductEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes catalogProductSimple::default diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ManageProductsStockTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ManageProductsStockTest.php new file mode 100644 index 0000000000000..f4161db15b8e6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ManageProductsStockTest.php @@ -0,0 +1,101 @@ +fixtureFactory = $fixtureFactory; + } + + /** + * Manage products stock. + * + * @param CatalogProductSimple $product + * @param string $skipAddingToCart + * @param string $configData + * @return mixed + */ + public function test(CatalogProductSimple $product, $skipAddingToCart = null, $configData = null) + { + $this->configData = $configData; + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + + // Preconditions + $product->persist(); + + // Steps + if (!$skipAddingToCart) { + $this->objectManager->create( + \Magento\Checkout\Test\TestStep\AddProductsToTheCartStep::class, + ['products' => [$product]] + )->run(); + + $cart['data']['items'] = ['products' => [$product]]; + + return ['cart' => $this->fixtureFactory->createByCode('cart', $cart)]; + } + } + + /** + * Set default configuration. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ManageProductsStockTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ManageProductsStockTest.xml new file mode 100644 index 0000000000000..165358a71334e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ManageProductsStockTest.xml @@ -0,0 +1,72 @@ + + + + + + default + Out of Stock + display_out_of_stock,backorders_allow_qty_below + + + + + product_with_category + Yes + 5 + Yes + 1 + Yes + 10000 + Yes + No + Yes + 1 + No + Out of Stock + Yes + + + + + product_with_category + Yes + 5 + In Stock + Yes + 1 + Yes + 10000 + Yes + No + Yes + 1 + No + Yes + + + + + product_with_category + Yes + 5 + In Stock + Yes + 1 + Yes + 10000 + Yes + No + Yes + 1 + No + Yes + display_out_of_stock + + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.php index f7fd82e3342bf..1c1077e0989a6 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.php @@ -1,15 +1,18 @@ productGrid = $productGrid; $this->attributeMassActionPage = $attributeMassActionPage; + $this->testStepFactory = $testStepFactory; + $this->fixtureFactory = $fixtureFactory; } /** * Run mass update product simple entity test. * - * @param CatalogProductSimple $initialProduct * @param CatalogProductSimple $product * @param string $configData + * @param array $initialProducts * @return array */ - public function test(CatalogProductSimple $initialProduct, CatalogProductSimple $product, $configData) + public function test(CatalogProductSimple $product, $configData, array $initialProducts) { $this->configData = $configData; // Preconditions - $initialProduct->persist(); + $products = $this->testStepFactory->create( + \Magento\Catalog\Test\TestStep\CreateProductsStep::class, + ['products' => $initialProducts] + )->run()['products']; $this->objectManager->create( \Magento\Config\Test\TestStep\SetupConfigurationStep::class, @@ -95,19 +121,33 @@ public function test(CatalogProductSimple $initialProduct, CatalogProductSimple // Steps $this->productGrid->open(); - $this->productGrid->getProductGrid()->updateAttributes([['sku' => $initialProduct->getSku()]]); + $this->productGrid->getProductGrid()->updateAttributes($products); $this->attributeMassActionPage->getAttributesBlockForm()->fill($product); $this->attributeMassActionPage->getFormPageActions()->save(); - $data = array_merge($initialProduct->getData(), $product->getData()); - $product = $this->objectManager->create( - \Magento\Catalog\Test\Fixture\CatalogProductSimple::class, - ['data' => $data] - ); - - return [ - 'category' => $initialProduct->getDataFieldConfig('category_ids')['source']->getCategories()[0], - 'product' => $product, - ]; + $updatedProducts = $this->prepareUpdatedProducts($products, $product); + + return ['products' => $updatedProducts]; + } + + /** + * Prepare updated products. + * + * @param array $products + * @param CatalogProductSimple $product + * @return array + */ + private function prepareUpdatedProducts(array $products, CatalogProductSimple $product) + { + $productsReturn = []; + /** @var FixtureInterface $item */ + foreach ($products as $item) { + $productsReturn[] = $this->fixtureFactory->create( + get_class($item), + ['data' => array_merge($item->getData(), $product->getData())] + ); + } + + return $productsReturn; } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.xml index 6f937999f3c34..487636c71e942 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/MassProductUpdateTest.xml @@ -1,7 +1,7 @@ @@ -9,11 +9,12 @@ product_flat - simple_10_dollar + catalogProductSimple::simple_10_dollar + catalogProductSimple::simple_10_dollar + 2 1.99 - diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php index 49fec0876e48f..4b3303d8676e3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php @@ -1,6 +1,6 @@ - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, stable:no simple1::catalogProductSimple::product_with_category,simple2::catalogProductSimple::product_with_category,config1::configurableProduct::two_options_with_fixed_price simple1:yes,simple2:yes,config1:no simple1:simple2,config1;config1:simple2 diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php index 37d8c9dc91d0c..f1701ab65fc50 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php @@ -1,6 +1,6 @@ - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, stable:no simple1::catalogProductSimple::product_with_category,simple2::catalogProductSimple::product_with_category,config1::configurableProduct::two_options_with_fixed_price simple1:simple2,config1;config1:simple2 simple1,config1,simple2 diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnCreationTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnCreationTest.php index c8189cd50ebf3..cdb5a21c397db 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnCreationTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnCreationTest.php @@ -1,6 +1,6 @@ + stable:no simple configurableProduct::default @@ -44,6 +45,7 @@ + stable:no virtual configurableProduct::not_virtual_for_type_switching @@ -56,6 +58,7 @@ + stable:no virtual downloadableProduct::default @@ -73,6 +76,7 @@ downloadable configurableProduct::not_virtual_for_type_switching + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php index 7c134c2902c33..3e10ed54cbe01 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ProductTypeSwitchingOnUpdateTest.php @@ -1,6 +1,6 @@ @@ -11,6 +11,7 @@ catalogProductSimple::default configurableProduct::default - + to_maintain:yes @@ -20,6 +21,7 @@ + to_maintain:yes catalogProductSimple::default catalogProductVirtual::default - @@ -27,6 +29,7 @@ + stable:no configurableProduct::default catalogProductSimple::product_without_category deleteVariations @@ -37,10 +40,12 @@ configurableProduct::default catalogProductVirtual::required_fields deleteVariations + to_maintain:yes + to_maintain:yes catalogProductVirtual::default catalogProductSimple::default - @@ -51,6 +56,7 @@ catalogProductVirtual::default configurableProduct::not_virtual_for_type_switching - + to_maintain:yes @@ -63,6 +69,7 @@ catalogProductVirtual::default downloadableProduct::default - + to_maintain:yes @@ -74,6 +81,7 @@ downloadableProduct::default catalogProductSimple::default - + to_maintain:yes @@ -81,6 +89,7 @@ downloadableProduct::default configurableProduct::not_virtual_for_type_switching - + to_maintain:yes @@ -90,6 +99,7 @@ + stable:no downloadableProduct::default catalogProductVirtual::default clearDownloadableData @@ -100,6 +110,7 @@ catalogProductSimple::default downloadableProduct::default - + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.php index f68ec539c62e0..b67244244a38e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.php @@ -1,16 +1,18 @@ productGrid = $productGrid; $this->editProductPage = $editProductPage; + $this->fixtureFactory = $fixtureFactory; } /** @@ -76,20 +88,25 @@ public function __inject( * * @param CatalogProductSimple $initialProduct * @param CatalogProductSimple $product + * @param Store|null $store * @param string $configData * @return array */ - public function test(CatalogProductSimple $initialProduct, CatalogProductSimple $product, $configData = '') - { + public function test( + CatalogProductSimple $initialProduct, + CatalogProductSimple $product, + Store $store = null, + $configData = '' + ) { $this->configData = $configData; // Preconditions $initialProduct->persist(); - $initialCategory = $initialProduct->hasData('category_ids') - ? $initialProduct->getDataFieldConfig('category_ids')['source']->getCategories()[0] - : null; - $category = $product->hasData('category_ids') && $product->getCategoryIds()[0] - ? $product->getDataFieldConfig('category_ids')['source']->getCategories()[0] - : $initialCategory; + $category = $this->getCategory($initialProduct, $product); + + if ($store) { + $store->persist(); + $productName[$store->getStoreId()] = $product->getName(); + } $this->objectManager->create( \Magento\Config\Test\TestStep\SetupConfigurationStep::class, @@ -101,10 +118,34 @@ public function test(CatalogProductSimple $initialProduct, CatalogProductSimple $this->productGrid->open(); $this->productGrid->getProductGrid()->searchAndOpen($filter); + if ($store) { + $this->editProductPage->getFormPageActions()->changeStoreViewScope($store); + } $this->editProductPage->getProductForm()->fill($product); $this->editProductPage->getFormPageActions()->save(); - return ['category' => $category]; + return [ + 'category' => $category, + 'stores' => isset($store) ? [$store] : [], + 'productNames' => isset($productName) ? $productName : [], + ]; + } + + /** + * Get Category instance. + * + * @param CatalogProductSimple $initialProduct + * @param CatalogProductSimple $product + * @return Category + */ + protected function getCategory(CatalogProductSimple $initialProduct, CatalogProductSimple $product) + { + $initialCategory = $initialProduct->hasData('category_ids') + ? $initialProduct->getDataFieldConfig('category_ids')['source']->getCategories()[0] + : null; + return $product->hasData('category_ids') && $product->getCategoryIds()[0] + ? $product->getDataFieldConfig('category_ids')['source']->getCategories()[0] + : $initialCategory; } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.xml index 323246949d1a5..c16de9401abb1 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateSimpleProductEntityTest.xml @@ -1,13 +1,14 @@ + stable:no Update visibility to Catalog, Search product_with_category Test simple product %isolation% @@ -24,6 +25,7 @@ + stable:no Update visibility to Not Visible Individually product_with_category Test simple product %isolation% @@ -47,6 +49,7 @@ test-simple-product-%isolation% 25.0000 Catalog + to_maintain:yes @@ -64,6 +67,7 @@ test-simple-product-%isolation% 89.0000 Search + to_maintain:yes @@ -81,6 +85,7 @@ Out of Stock test-simple-product-%isolation% 125.0000 + to_maintain:yes @@ -89,6 +94,7 @@ + stable:no Update product status to offline product_with_category Test simple product %isolation% @@ -112,6 +118,7 @@ 87 test-simple-product-%isolation% 333.0000 + to_maintain:yes @@ -124,6 +131,7 @@ test_simple_product_%isolation% 133.00 test-simple-product-%isolation% + to_maintain:yes @@ -142,8 +150,42 @@ sku_simple_product_%isolation% 1.99 default + to_maintain:yes + + stable:no + product_with_category + Test simple product %isolation% + test_simple_product_%isolation% + 245.00 + 200 + drop_down_with_one_option_percent_price + simple_drop_down_with_one_option_percent_price + test-simple-product-%isolation% + 120.0000 + + + + + + product_with_category + custom + No + Test simple product %isolation% + + + + + test_type:acceptance_test, test_type:extended_acceptance_test + price_scope_website + product_with_category + custom + No + 9.99 + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateVirtualProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateVirtualProductEntityTest.php index ddd788d7ee1c9..c4ca136d19857 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateVirtualProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/UpdateVirtualProductEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.php index a8c375ba2d849..f7b4821fd984a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ValidateOrderOfProductTypeTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateAttributeSetEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateAttributeSetEntityTest.php index d3bd8f44adb74..09e99d8edfb23 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateAttributeSetEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateAttributeSetEntityTest.php @@ -1,6 +1,6 @@ + stable:no AttributeSet%isolation% default diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityFromProductPageTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityFromProductPageTest.php index 0a85628c5e708..3b980dc4ff458 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityFromProductPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityFromProductPageTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityTest.php index 22325ead5f5f7..97869978c1a38 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/CreateProductAttributeEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes custom_attribute_set Text_Field_Admin_%isolation% Text Field @@ -18,7 +19,7 @@ - + custom_attribute_set Text_Field_Admin_%isolation% Text Area @@ -35,6 +36,7 @@ product-details + @@ -57,6 +59,7 @@ Yes Yes Yes + to_maintain:yes @@ -65,6 +68,7 @@ + to_maintain:yes custom_attribute_set Yes/No_Admin_%isolation% Yes/No @@ -97,6 +101,7 @@ Yes Yes Yes + to_maintain:yes @@ -109,7 +114,7 @@ - + test_type:extended_acceptance_test custom_attribute_set Dropdown_Admin_%isolation% @@ -134,6 +139,7 @@ product-details + @@ -147,7 +153,7 @@ - + custom_attribute_set Price_Admin_%isolation% Price @@ -163,12 +169,14 @@ 15 + + to_maintain:yes custom_attribute_set Fixed_Product_Tax_Admin_%isolation% Fixed Product Tax @@ -185,6 +193,7 @@ + to_maintain:yes custom_attribute_set Text_Field_Admin_%isolation% Text Field diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAssignedToTemplateProductAttributeTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAssignedToTemplateProductAttributeTest.php index 11958cc2c1e87..5387cc64777d6 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAssignedToTemplateProductAttributeTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAssignedToTemplateProductAttributeTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAttributeSetTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAttributeSetTest.php index b097dc4681b16..0f29988433b05 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAttributeSetTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteAttributeSetTest.php @@ -1,6 +1,6 @@ + stable:no custom_attribute_set default default diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.php index 737a086dbb7e9..2de11d140c57a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.php @@ -1,6 +1,6 @@ @@ -15,6 +15,7 @@ + stable:no attribute_type_dropdown diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteSystemProductAttributeTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteSystemProductAttributeTest.php index 20fee003a576d..7de3950f02ab7 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteSystemProductAttributeTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteSystemProductAttributeTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.php index baf9a238c6bc0..2b165af09ecbd 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteUsedInConfigurableProductAttributeTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateAttributeSetTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateAttributeSetTest.php index af6b5747819cd..a3306095e464d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateAttributeSetTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateAttributeSetTest.php @@ -1,6 +1,6 @@ + stable:no AttributeSetEdit1%isolation% Custom-group%isolation% custom_attribute_set diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.php index 399b918078f22..c6de3421867a5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes custom_attribute_set attribute_type_text_field Text_Field_%isolation% @@ -28,6 +29,7 @@ + to_maintain:yes custom_attribute_set attribute_type_dropdown Dropdown_%isolation% @@ -60,6 +62,7 @@ FPC + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddAttributeToAttributeSetStep.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddAttributeToAttributeSetStep.php index 95d93db00b874..aaf0615b5e981 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddAttributeToAttributeSetStep.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/AddAttributeToAttributeSetStep.php @@ -1,6 +1,6 @@ product = $product; + $this->catalogProductView = $catalogProductView; + $this->browser = $browser; + } + + /** + * Configure product. + * + * @return void + */ + public function run() + { + $this->browser->open($_ENV['app_frontend_url'] . $this->product->getUrlKey() . '.html'); + $this->catalogProductView->getViewBlock()->configure($this->product); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateAttributeSetStep.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateAttributeSetStep.php index 9a0ce0ac2039b..667164db3514f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateAttributeSetStep.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateAttributeSetStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml index 82a7c263b1ca9..5a2704377aebe 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml @@ -1,7 +1,7 @@ @@ -167,7 +167,7 @@ [name="product[%code%]"] null - + [name="product[%code%]"] datepicker diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml index 40e9a20adf3b3..4ff22ca1b4388 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/testcase.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/ui/di.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/ui/di.xml index ca217a26610f3..fc2422885a5e7 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/ui/di.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/ui/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/webapi/di.xml index 0e441656558d5..b813b4609a355 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogInventory/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/CatalogInventory/Test/Repository/ConfigData.xml index 8e5888431b3b2..35e6138f38df6 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogInventory/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogInventory/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -25,6 +25,15 @@ + + + cataloginventory + 1 + No + 0 + + + cataloginventory @@ -42,5 +51,14 @@ 0 + + + + cataloginventory + 1 + Yes + 1 + + diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/FormPageActions.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/FormPageActions.php index a3cae9dbbf32b..4952d9dca4eda 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/FormPageActions.php @@ -1,6 +1,6 @@ \Magento\CatalogRule\Test\Block\Adminhtml\Promo\Catalog\Edit\Section\RuleInformation - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::input[@name='name']] - xpath + [data-index="rule_information"] + css selector select @@ -26,19 +26,20 @@ \Magento\CatalogRule\Test\Block\Adminhtml\Promo\Catalog\Edit\Section\Conditions - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::div[@class='rule-tree']] - xpath + [data-index="block_promo_catalog_edit_tab_conditions"] + css selector [id^="catalog_rule_formrule_conditions_fieldset_"] + css selector conditions \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::select[@name='simple_action']] - xpath + [data-index="actions"] + css selector select diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/Promo/Catalog/Edit/Section/Conditions.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/Promo/Catalog/Edit/Section/Conditions.php index d82d63fcabc68..fad9dea041cda 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/Promo/Catalog/Edit/Section/Conditions.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Block/Adminhtml/Promo/Catalog/Edit/Section/Conditions.php @@ -1,6 +1,6 @@ isVisible(), 'Price block is not displayed for product ' . $product->getName() ); - $actualPrice['regular'] = (float)$priceBlock->getOldPrice(); $actualPrice['special'] = (float)$priceBlock->getSpecialPrice(); - $actualPrice['discount_amount'] = $actualPrice['regular'] - $actualPrice['special']; + if ($productPrice[$key]['regular'] !== 'No') { + $actualPrice['regular'] = (float)$priceBlock->getOldPrice(); + $actualPrice['discount_amount'] = $actualPrice['regular'] - $actualPrice['special']; + } $diff = $this->verifyData($actualPrice, $productPrice[$key]); \PHPUnit_Framework_Assert::assertTrue( empty($diff), diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php index 653792417be5a..508a2762d111e 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php @@ -1,6 +1,6 @@ getViewBlock()->waitLoader(); $productPriceBlock = $catalogProductViewPage->getViewBlock()->getPriceBlock(); - $actualPrice['regular'] = $productPriceBlock->getOldPrice(); $actualPrice['special'] = $productPriceBlock->getSpecialPrice(); - $actualPrice['discount_amount'] = $actualPrice['regular'] - $actualPrice['special']; + if ($productPrice[$key]['regular'] !== 'No') { + $actualPrice['regular'] = $productPriceBlock->getOldPrice(); + $actualPrice['discount_amount'] = $actualPrice['regular'] - $actualPrice['special']; + } $diff = $this->verifyData($actualPrice, $productPrice[$key]); \PHPUnit_Framework_Assert::assertTrue( empty($diff), diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php index 139ef99f19870..8be4c4cf3c823 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Handler/CatalogRule/CatalogRuleInterface.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Handler/CatalogRule/CatalogRuleInterface.php index d7d26d356a401..de5bbdb012477 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Handler/CatalogRule/CatalogRuleInterface.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Handler/CatalogRule/CatalogRuleInterface.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleIndex.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleIndex.xml index 0c575781c5238..37c4180699d96 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleIndex.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleNew.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleNew.xml index e1c6f4493f27c..a1d0a803cb3b1 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleNew.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Page/Adminhtml/CatalogRuleNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Repository/CatalogRule.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Repository/CatalogRule.xml index 5c36d51aa06db..e2357a2b8fa6e 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Repository/CatalogRule.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Repository/CatalogRule.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/AbstractCatalogRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/AbstractCatalogRuleEntityTest.php index da79894dba8d0..40bd3e694c0bb 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/AbstractCatalogRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/AbstractCatalogRuleEntityTest.php @@ -1,6 +1,6 @@ persist(); - - foreach ($catalogRules as $catalogPriceRule) { - $catalogPriceRule = $this->createCatalogPriceRule($catalogPriceRule, $product, $customer); + $this->promo = $promo; + if ($customer !== null) { + $customer->persist(); + } - if ($isCronEnabled) { - $cron->run(); - $cron->run(); - } else { - $catalogRuleEdit->open(['id' => $catalogPriceRule->getId()]); - $this->catalogRuleNew->getFormPageActions()->saveAndApply(); + $products = $stepFactory->create( + \Magento\Catalog\Test\TestStep\CreateProductsStep::class, + ['products' => $products] + )->run()['products']; + + foreach ($catalogRules as $catalogRule) { + foreach ($products as $product) { + $catalogPriceRule = $this->createCatalogPriceRule($catalogRule, $product, $customer); + if ($isCronEnabled) { + $cron->run(); + $cron->run(); + } else { + $catalogRuleEdit->open(['id' => $catalogPriceRule->getId()]); + $this->catalogRuleNew->getFormPageActions()->saveAndApply(); + } } } - - return ['products' => [$product]]; + return ['products' => $products]; } /** * Prepare condition for catalog price rule. * - * @param CatalogProductSimple $productSimple + * @param FixtureInterface $product * @param array $catalogPriceRule * @return array */ - private function prepareCondition(CatalogProductSimple $productSimple, array $catalogPriceRule) + protected function prepareCondition(FixtureInterface $product, array $catalogPriceRule) { - $result = []; $conditionEntity = explode('|', trim($catalogPriceRule['data']['rule'], '[]'))[0]; - - switch ($conditionEntity) { - case 'Category': - $result['%category_id%'] = $productSimple->getDataFieldConfig('category_ids')['source']->getIds()[0]; - break; - case 'Attribute': - /** @var \Magento\Catalog\Test\Fixture\CatalogProductAttribute[] $attrs */ - $attributes = $productSimple->getDataFieldConfig('attribute_set_id')['source'] - ->getAttributeSet()->getDataFieldConfig('assigned_attributes')['source']->getAttributes(); - - $result['%attribute_id%'] = $attributes[0]->getAttributeCode(); - $result['%attribute_value%'] = $attributes[0]->getOptions()[0]['id']; - break; - } - foreach ($result as $key => $value) { - $catalogPriceRule['data']['rule'] = str_replace($key, $value, $catalogPriceRule['data']['rule']); + $actionName = 'get' . $conditionEntity; + if (method_exists($this, $actionName)) { + $result = $this->$actionName($product); + foreach ($result as $key => $value) { + $catalogPriceRule['data']['rule'] = str_replace($key, $value, $catalogPriceRule['data']['rule']); + } + return $catalogPriceRule; + } else { + $message = sprintf('Method "%s" does not exist in %s', $actionName, get_class($this)); + throw new \BadMethodCallException($message); } + } - return $catalogPriceRule; + /** + * Add category_id to catalog price rule. + * + * @param FixtureInterface $product + * @return array + */ + protected function getCategory(FixtureInterface $product) + { + $result['%category_id%'] = $product->getDataFieldConfig('category_ids')['source']->getIds()[0]; + return $result; + } + + /** + * Add attribute_id to catalog price rule. + * + * @param FixtureInterface $product + * @return array + */ + protected function getAttribute(FixtureInterface $product) + { + $attributes = $product->getDataFieldConfig('attribute_set_id')['source'] + ->getAttributeSet()->getDataFieldConfig('assigned_attributes')['source']->getAttributes(); + $result['%attribute_id%'] = $attributes[0]->getAttributeCode(); + $result['%attribute_value%'] = $attributes[0]->getOptions()[$this->promo]['id']; + return $result; } /** @@ -108,9 +147,8 @@ private function prepareCondition(CatalogProductSimple $productSimple, array $ca * @param Customer $customer * @return array */ - private function applyCustomerGroup(array $catalogPriceRule, Customer $customer) + protected function applyCustomerGroup(array $catalogPriceRule, Customer $customer) { - $customer->persist(); /** @var \Magento\Customer\Test\Fixture\CustomerGroup $customerGroup */ $customerGroup = $customer->getDataFieldConfig('group_id')['source']->getCustomerGroup(); $catalogPriceRule['data']['customer_group_ids']['option_0'] = $customerGroup->getCustomerGroupId(); @@ -121,20 +159,19 @@ private function applyCustomerGroup(array $catalogPriceRule, Customer $customer) /** * Create catalog price rule. * - * @param CatalogProductSimple $product * @param array $catalogPriceRule + * @param FixtureInterface $product * @param Customer $customer * @return CatalogRule */ - private function createCatalogPriceRule( + protected function createCatalogPriceRule( array $catalogPriceRule, - CatalogProductSimple $product, + FixtureInterface $product, Customer $customer = null ) { if (isset($catalogPriceRule['data']['rule'])) { $catalogPriceRule = $this->prepareCondition($product, $catalogPriceRule); } - if ($customer !== null) { $catalogPriceRule = $this->applyCustomerGroup($catalogPriceRule, $customer); } diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml index c732ae1f2b877..828a8ee956683 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/ApplyCatalogPriceRulesTest.xml @@ -1,7 +1,7 @@ @@ -11,7 +11,7 @@ test_type:extended_acceptance_test catalog_price_rule_priority_0 catalog_price_rule_priority_2 - simple_for_salesrule_2 + catalogProductSimple::simple_for_salesrule_2 15 20 35 @@ -26,7 +26,7 @@ catalog_price_rule_priority_0 catalog_price_rule_priority_1_stop_further_rules catalog_price_rule_priority_2 - simple_for_salesrule_2 + catalogProductSimple::simple_for_salesrule_2 20 25 30 @@ -40,7 +40,7 @@ active_catalog_price_rule_with_conditions active_catalog_rule - simple_for_salesrule_2 + catalogProductSimple::simple_for_salesrule_2 45 50 5 @@ -53,7 +53,7 @@ test_type:extended_acceptance_test - product_with_custom_color_attribute + catalogProductSimple::product_with_custom_color_attribute Catalog Price Rule %isolation% Active Main Website @@ -72,7 +72,7 @@ - MAGETWO-23036 + catalogProductSimple::MAGETWO-23036 rule_name%isolation% Active Main Website @@ -93,7 +93,7 @@ test_type:acceptance_test, test_type:extended_acceptance_test customer_with_new_customer_group - simple_10_dollar + catalogProductSimple::simple_10_dollar rule_name%isolation% Active Main Website @@ -113,5 +113,87 @@ + + catalogProductSimple::with_default_custom_option + catalogProductSimple::with_percent_and_fixed_custom_option + catalogProductSimple::with_custom_options_and_price_56_78 + customer_US + CatalogPriceRule %isolation% + Active + Main Website + default + Apply as percentage of original + 13 + Yes + 164.99 + 179.99 + 7.38 + 8.04 + 7.38 + 49.40 + 53.85 + 61.74 + 49.40 + 61.74 + 53.85 + 56.78 + 61.98 + 69.12 + Flat Rate + Fixed + UK_address + free + + + + + configurableProduct::product_with_price_10 + catalogProductSimple::simple_10_dollar + NOT LOGGED IN + CatalogPriceRule %isolation% + Yes + Active + Main Website + Apply as percentage of original + 10 + 18 + 28 + 9 + 9 + No + 9 + 9 + 10 + 1 + customer_US + default + Flat Rate + Fixed + UK_address + checkmo + + + + + + catalogProductSimple::with_fixed_custom_option_price_100 + customer_US + CatalogPriceRule %isolation% + Active + Main Website + default + Apply as percentage of original + 10 + 125 + 130 + 90 + 100 + 10 + 125 + Flat Rate + Fixed + + + diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/CreateCatalogPriceRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/CreateCatalogPriceRuleEntityTest.php index f5efc258fbdbf..9babd75cc6a12 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/CreateCatalogPriceRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/CreateCatalogPriceRuleEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.php index a2d0ff9500d4c..fbbb760bb4484 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.php @@ -1,6 +1,6 @@ Catalog Price Rules. @@ -25,7 +27,7 @@ * 5. Perform all assertions. * * @group Catalog_Price_Rules - * @ZephyrId MAGETWO-25211 + * @ZephyrId MAGETWO-25211, MAGETWO-20431 */ class DeleteCatalogPriceRuleEntityTest extends Injectable { @@ -46,7 +48,7 @@ class DeleteCatalogPriceRuleEntityTest extends Injectable * @var CatalogRuleNew */ protected $catalogRuleNew; - + /** * Injection data. * @@ -67,13 +69,18 @@ public function __inject( * * @param CatalogRule $catalogPriceRule * @param string $product + * @param Customer|null $customer * @return array */ - public function test(CatalogRule $catalogPriceRule, $product) + public function test(CatalogRule $catalogPriceRule, $product, Customer $customer = null) { // Precondition $catalogPriceRule->persist(); + if ($customer) { + $customer->persist(); + } + $filter = [ 'name' => $catalogPriceRule->getName(), 'rule_id' => $catalogPriceRule->getId(), diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml index ed469088ca3c4..f01be676e1789 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml @@ -1,21 +1,28 @@ - + active_catalog_price_rule_with_conditions catalogProductSimple::simple_for_salesrule_1 - 100 + customer_US + 100 + 100 + 105 + Flat Rate + Fixed + checkmo + diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml index 554da2b1264cf..6b98c1f5fe6dc 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/UpdateCatalogPriceRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/UpdateCatalogPriceRuleEntityTest.php index 8ca54baed577c..2b4e972c1120d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/UpdateCatalogPriceRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/UpdateCatalogPriceRuleEntityTest.php @@ -1,6 +1,6 @@ @@ -44,7 +44,7 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestStep/CreateCatalogRuleStep.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestStep/CreateCatalogRuleStep.php index 7c0ce4e759805..10ef5a83db84d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestStep/CreateCatalogRuleStep.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestStep/CreateCatalogRuleStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/di.xml index 41032133aedfd..6f0c0afdc9693 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/ui/di.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/ui/di.xml index 1d81719d921fe..9005bb379050b 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/ui/di.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/etc/ui/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.php b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.php new file mode 100644 index 0000000000000..9ee3b203698b5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.php @@ -0,0 +1,50 @@ +hasData('configurable_attributes_data')) { + $attributes = $product->getDataFieldConfig('configurable_attributes_data')['source'] + ->getAttributesData()['attribute_key_0']; + $result['%attribute_id%'] = $attributes['attribute_code']; + $result['%attribute_value%'] = $attributes['options']['option_key_' . $this->promo]['id']; + return $result; + } else { + return parent::getAttribute($product); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml new file mode 100644 index 0000000000000..75ef7dd5dea86 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/ApplyConfigurableProductCatalogPriceRulesTest.xml @@ -0,0 +1,76 @@ + + + + + + configurableProduct::Stellar_Solar_Jacket_SIZE_S + configurableProduct::Stellar_Solar_Jacket_SIZE_M + configurableProduct::Stellar_Solar_Jacket_SIZE_L + 2 + Catalog Price Rule %isolation% + Active + Main Website + NOT LOGGED IN + [Attribute|%attribute_id%|is|%attribute_value%] + Apply as fixed amount + 0.55 + 224.45 + 239.45 + 74.45 + 75 + No + 74.45 + 75 + No + 74.45 + 74.45 + No + Flat Rate + Fixed + UK_address + checkmo + + + + + configurableProduct::first_product_with_custom_options_and_option_key_1 + configurableProduct::first_product_with_custom_options_and_option_key_2 + configurableProduct::second_product_with_custom_options_and_option_key_1 + configurableProduct::second_product_with_custom_options_and_option_key_2 + customer_US + default + NOT LOGGED IN + CatalogPriceRule %isolation% + Active + Main Website + Apply as fixed amount + Yes + 5 + 382 + 402 + 15.01 + 86.99 + No + 15.01 + 163.99 + No + 15.01 + 27.01 + No + 15.01 + 104.01 + No + Flat Rate + Fixed + UK_address + checkmo + + + + + diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml index 0edef63c95e66..15fd7e2a58e7a 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/TestCase/DeleteCatalogPriceRuleEntityTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Edit/SearchTermForm.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Edit/SearchTermForm.php index ce7bccf38a6a1..113484f3ecc66 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Edit/SearchTermForm.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Edit/SearchTermForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Grid.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Grid.php index f9efb63b11705..367380512e75d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Grid.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Adminhtml/Grid.php @@ -1,6 +1,6 @@ dataMapping($data); @@ -86,12 +90,19 @@ public function fill(FixtureInterface $fixture, SimpleElement $element = null) /** @var CatalogProductAttribute $attribute */ $attribute = $fixture->getDataFieldConfig('custom_attribute')['source']->getAttribute(); $attributeType = $attribute->getFrontendInput(); + if ($attributeType == 'Text Area') { + $attributeType = 'Text Field'; + } $attributeCode = $attribute->getAttributeCode(); } if ($this->hasRender($attributeType)) { $element = $this->_rootElement->find(sprintf($this->customAttributeSelector, $attributeCode)); $arguments = ['fixture' => $fixture, 'element' => $element, 'mapping' => $mapping]; $this->callRender($attributeType, 'fill', $arguments); + } elseif ($attributeType == 'Price') { + $value = $data['custom_attribute']['value']; + $this->_rootElement->find('#' . $attributeCode)->setValue($value); + $this->_rootElement->find('#' . $attributeCode . '_to')->setValue($value); } else { $this->_fill($mapping, $element); } diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Form.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Form.xml index 5cbcfdf974099..62781f1ac73a6 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Form.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Form.xml @@ -1,7 +1,7 @@ @@ -25,5 +25,11 @@ #price_to + + #weight + + + #weight_to + diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Result.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Result.php index dd6ec59c4e553..48c581df36b61 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Result.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Block/Advanced/Result.php @@ -1,6 +1,6 @@ _rootElement->find(sprintf($this->searchResultsFor), Locator::SELECTOR_CSS) + ->getText(); + preg_match("~Search results for: \'(.*)\'~", $searchQueryResult, $matches); + $query = isset($matches[1]) ? $matches[1] : null; + return $query; + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchEmptyTerm.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchEmptyTerm.php new file mode 100644 index 0000000000000..66f024efd0dc1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchEmptyTerm.php @@ -0,0 +1,49 @@ +getMessagesBlock()->getErrorMessage(); + \PHPUnit_Framework_Assert::assertEquals( + self::ERROR_MESSAGE, + $actualMessage, + 'Wrong error message is displayed.' + . "\nExpected: " . self::ERROR_MESSAGE + . "\nActual: " . $actualMessage + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Correct specify search term error message is displayed.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php index 0f1fbfda509d5..1f47872ee18f5 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php @@ -1,6 +1,6 @@ fixtureFactory = $fixtureFactory; $cmsIndex->open(); $cmsIndex->getFooterBlock()->openAdvancedSearch(); $searchForm = $searchPage->getForm(); - $productSearch = $this->prepareFixture($product); + $productSearch = $this->prepareFixture($product, $attributeValue); $searchForm->fill($productSearch); $searchForm->submit(); @@ -63,11 +65,15 @@ public function processAssert( * Preparation of fixture data before comparing. * * @param InjectableFixture $productSearch + * @param int|null $attributeValue * @return CatalogProductSimple */ - protected function prepareFixture(InjectableFixture $productSearch) + protected function prepareFixture(InjectableFixture $productSearch, $attributeValue) { $customAttribute = $productSearch->getDataFieldConfig('custom_attribute')['source']->getAttribute(); + if ($attributeValue !== null) { + $customAttribute = ['value' => $attributeValue, 'attribute' => $customAttribute]; + } return $this->fixtureFactory->createByCode( 'catalogProductSimple', ['data' => ['custom_attribute' => $customAttribute]] diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductResult.php new file mode 100644 index 0000000000000..9c9eeaa23a756 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductResult.php @@ -0,0 +1,102 @@ +prepareExpectedResult($isVisibleInAdvancedSearch, $allProducts); + $foundedProducts = $this->advancedSearchProducts($resultPage, $allProducts); + \PHPUnit_Framework_Assert::assertEquals( + $expectedResult, + $foundedProducts, + 'Expected and founded products not the same.' + . "\nExpected: " . print_r($expectedResult) + . "\nActual: " . print_r($foundedProducts) + ); + } + + /** + * Returns array with expected products. + * + * @param array $isVisibleInAdvancedSearch + * @param array $products + * @return array + */ + private function prepareExpectedResult(array $isVisibleInAdvancedSearch, array $products) + { + $expectedResult = []; + foreach ($isVisibleInAdvancedSearch as $key => $value) { + if ($value == "Yes") { + $expectedResult[] = sprintf(self::FOUNDED_PRODUCT_MESSAGE, $products[$key]->getName()); + } + } + sort($expectedResult); + return $expectedResult; + } + + /** + * Returns array with found products. + * + * @param AdvancedResult $resultPage + * @param array $allProducts + * @return array + */ + private function advancedSearchProducts(AdvancedResult $resultPage, array $allProducts) + { + $products = $allProducts; + $foundedProducts = []; + do { + $dirtKeys = []; + foreach ($allProducts as $key => $product) { + $isProductVisible = $resultPage->getListProductBlock()->getProductItem($product)->isVisible(); + if ($isProductVisible) { + $foundedProducts[] = sprintf(self::FOUNDED_PRODUCT_MESSAGE, $products[$key]->getName()); + $dirtKeys[] = $key; + } + } + foreach ($dirtKeys as $key) { + unset($products[$key]); + } + } while ($resultPage->getBottomToolbar()->nextPage() && (count($products) > 0)); + sort($foundedProducts); + return $foundedProducts; + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'All products are involved in the search were found successfully.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php index 5200a0268cabe..5d99505df3eea 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php @@ -1,6 +1,6 @@ getSearchResultsTitleBlock()->getSearchQuery()), + 128, + 'Search query length is not truncated to 128 symbols.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Search query truncated to 128 symbols.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php index b1f2c8aea90e8..1aad5a9a0c267 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php @@ -1,6 +1,6 @@ getDataFieldConfig('query_text')['source']->getProduct(); + + $isProductVisible = $resultPage->getListProductBlock()->getProductItem($product)->isVisible(); + while (!$isProductVisible && $resultPage->getBottomToolbar()->nextPage()) { + $isProductVisible = $resultPage->getListProductBlock()->getProductItem($product)->isVisible(); + } + $productName = $product->getName(); + + \PHPUnit_Framework_Assert::assertTrue($isProductVisible, "A product with name $productName was not found."); + $resultPage->getListProductBlock()->getProductItem($product)->clickAddToCart(); + $catalogProductView->getViewBlock()->waitLoader(); + if (isset($product->getCheckoutData()['options'])) { + $catalogProductView->getViewBlock()->addToCart($product); + $message = $catalogProductView->getMessagesBlock()->getSuccessMessage(); + } else { + $message = $resultPage->getMessagesBlock()->getSuccessMessage(); + } + + \PHPUnit_Framework_Assert::assertEquals( + sprintf(self::SUCCESS_MESSAGE, $productName), + $message + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product was successfully added to cart from the search results page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php index 1c8c258c36e5a..7235b78f783ab 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php @@ -1,6 +1,6 @@ open(); + $availableAttributes = $advancedSearch->getForm()->getFormLabels(); + if (isset($attributeForSearch['isVisible'])) { + \PHPUnit_Framework_Assert::assertTrue( + (false !== array_search($attributeForSearch['name'], $availableAttributes)), + 'Attribute ' . $attributeForSearch['name'] . 'was not found in Advanced Search Page.' + ); + } else { + \PHPUnit_Framework_Assert::assertTrue( + (false == array_search($attributeForSearch['name'], $availableAttributes)), + 'Attribute ' . $attributeForSearch['name'] . ' was found in Advanced Search Page.' + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Attribute was found in Advanced Search Page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php index 77d701fcd851d..0d6d9c10cb4aa 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Fixture/CatalogSearchQuery/QueryText.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Fixture/CatalogSearchQuery/QueryText.php index c20f72fcdc287..2b87f9dcbe5a8 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Fixture/CatalogSearchQuery/QueryText.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Fixture/CatalogSearchQuery/QueryText.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/Adminhtml/CatalogSearchIndex.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/Adminhtml/CatalogSearchIndex.xml index 82c1af40bb4f4..c62f5a5d5de4b 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/Adminhtml/CatalogSearchIndex.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/Adminhtml/CatalogSearchIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedResult.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedResult.xml index 6575c452cbcbd..e3d2968878a3d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedResult.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedResult.xml @@ -1,7 +1,7 @@ @@ -10,5 +10,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedSearch.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedSearch.xml index 76d4b4f1df939..dbda62e2109b3 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedSearch.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/AdvancedSearch.xml @@ -1,7 +1,7 @@ @@ -15,5 +15,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/CatalogsearchResult.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/CatalogsearchResult.xml index 49ee4cd35e9c8..d7f1961beb5a8 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/CatalogsearchResult.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Page/CatalogsearchResult.xml @@ -1,7 +1,7 @@ @@ -10,5 +10,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Repository/CatalogSearchQuery.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Repository/CatalogSearchQuery.xml index f004b8b52824b..bb55240acc650 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Repository/CatalogSearchQuery.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Repository/CatalogSearchQuery.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php index a3e5a4ba850d4..6256505595c19 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/AdvancedSearchEntityTest.php @@ -1,6 +1,6 @@ @@ -116,5 +116,10 @@ Negative_product_search + + MAGETWO-18537: "Please specify at least one search term." error message is missed in Advanced Search + + + diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/CreateSearchTermEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/CreateSearchTermEntityTest.php index f6ffd84c0b4e9..063f78cafdc6e 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/CreateSearchTermEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/CreateSearchTermEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/DeleteSearchTermEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/DeleteSearchTermEntityTest.php index ab5fb5f5bcd4d..b3c773e2372cd 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/DeleteSearchTermEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/DeleteSearchTermEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/MassDeleteSearchTermEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/MassDeleteSearchTermEntityTest.php index 5f41d187564f9..035b3bfe98b86 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/MassDeleteSearchTermEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/MassDeleteSearchTermEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml index 9059ae2927d0d..6555556ed6f4e 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.php index c845e7f0bfe85..87c92bd0ba1b3 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.php @@ -1,6 +1,6 @@ cmsIndex->open(); - $this->cmsIndex->getSearchBlock()->search($catalogSearch->getQueryText()); + $this->cmsIndex->getSearchBlock()->search($catalogSearch->getQueryText(), $queryLength); } } diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml index 3f8e5191a80f7..8380ef85dad4d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml @@ -1,7 +1,7 @@ @@ -12,38 +12,31 @@ catalogProductSimple::default::sku - - Search simple product + catalogProductSimple::default::simple - + - - Search virtual product + catalogProductVirtual::default::virtual - + - - Search configurable product + configurableProduct::default::configurable - + - - Search downloadable product + downloadableProduct::default::downloadable - + - - Search grouped product - groupedProduct::default::grouped - + + groupedProduct::withSimpleProducts_without_qty::grouped + - - Search bundle dynamic product + bundleProduct::bundle_dynamic_product::bundle - + - - Search fixed product + bundleProduct::bundle_fixed_product::bundle @@ -60,5 +53,27 @@ + + catalogProductSimple::default::name + 2 + + + + + catalogProductSimple::default::name + 3 + + + + catalogProductSimple::product_with_long_name::name + 128 + + + + catalogProductSimple::product_with_long_name::name + 129 + + + diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SuggestSearchingResultEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SuggestSearchingResultEntityTest.php index 42c1683a6cd14..4a8fa016cbfbd 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SuggestSearchingResultEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SuggestSearchingResultEntityTest.php @@ -1,6 +1,6 @@ + stable:no catalogProductSimple::name - + stable:no catalogProductSimple::sku 1 diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/UpdateSearchTermEntityTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/UpdateSearchTermEntityTest.php index 291f71322ded5..5f1b10465dbae 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/UpdateSearchTermEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/UpdateSearchTermEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/curl/di.xml index a28818d50b72c..0dd9699f2213f 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/di.xml index 59b207fe0c6ad..5816efb9386a0 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml new file mode 100644 index 0000000000000..a92a21d3fe42d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Block/Adminhtml/Category/Edit/CategoryForm.xml @@ -0,0 +1,17 @@ + + + + + + + checkbox + input[name='url_key_create_redirect'] + + + + diff --git a/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Fixture/Category.xml b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Fixture/Category.xml new file mode 100644 index 0000000000000..957a8100dc327 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Fixture/Category.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php index e8178d07a1e9e..4936bb7922716 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php @@ -1,6 +1,6 @@ blockFactory->create( - \Magento\Checkout\Test\Block\Cart\CartItem::class, + $this->cartItemClass, ['element' => $cartItemBlock] ); } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/AbstractCartItem.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/AbstractCartItem.php index 1181c1a8d4d51..089189cd7bec0 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/AbstractCartItem.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/AbstractCartItem.php @@ -1,6 +1,6 @@ openEstimateShippingAndTax(); + $mapping = $this->dataMapping(array_flip(['country_id'])); + $countryField = $this->getElement($this->_rootElement, $mapping['country_id']); + $this->_rootElement->waitUntil( + function () use ($countryField) { + return $countryField->isVisible() ? true : null; + } + ); + return array_map( + function ($option) { + return $option->getAttribute('value'); + }, + $countryField->getElements($this->topOptions, Locator::SELECTOR_XPATH) + ); + } + /** * Select shipping method. * @@ -86,16 +116,17 @@ public function openEstimateShippingAndTax() */ public function selectShippingMethod(array $shipping) { - $selector = sprintf($this->shippingMethod, $shipping['shipping_service'], $shipping['shipping_method']); - if (!$this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->isVisible()) { - $this->openEstimateShippingAndTax(); - } - - $element = $this->_rootElement->find($selector, Locator::SELECTOR_XPATH); - if (!$element->isDisabled()) { - $element->click(); - } else { - throw new \Exception("Unable to set value to field '$selector' as it's disabled."); + if (isset($shipping['shipping_service']) && isset($shipping['shipping_method'])) { + $selector = sprintf($this->shippingMethod, $shipping['shipping_service'], $shipping['shipping_method']); + if (!$this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->isVisible()) { + $this->openEstimateShippingAndTax(); + } + $element = $this->_rootElement->find($selector, Locator::SELECTOR_XPATH); + if (!$element->isDisabled()) { + $element->click(); + } else { + throw new \Exception("Unable to set value to field '$selector' as it's disabled."); + } } } @@ -167,7 +198,7 @@ public function waitForUpdatedShippingMethods() } /** - * Wait for common shipping price block to appear + * Wait for common shipping price block to appear. * * @return void */ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.xml index ea36a0b027269..e374a551e7bbb 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Shipping.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php index cbda80aa712f0..0797b1f8c8911 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php @@ -1,6 +1,6 @@ click(); } + /** + * Click "Proceed to Checkout" button. + * + * @return void + */ + public function clickProceedToCheckoutButton() + { + $this->_rootElement->find($this->proceedToCheckoutButton)->click(); + } + /** * Wait counter qty visibility. * @@ -134,7 +151,7 @@ function () use ($browser, $selector) { } /** - * Get empty minicart message + * Get empty minicart message. * * @return string */ @@ -145,7 +162,7 @@ public function getEmptyMessage() } /** - * Is minicart items quantity block visible + * Is minicart items quantity block visible. * * @return bool */ @@ -154,6 +171,16 @@ public function isItemsQtyVisible() return $this->_rootElement->find($this->productCounter, Locator::SELECTOR_XPATH)->isVisible(); } + /** + * Get qty of items in minicart. + * + * @return int + */ + public function getItemsQty() + { + return (int)$this->_rootElement->find($this->productCounter, Locator::SELECTOR_XPATH)->getText(); + } + /** * Get subtotal. * diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar/Item.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar/Item.php index b171a7062e942..d99751d285f4c 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar/Item.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar/Item.php @@ -1,6 +1,6 @@ waitForElementNotVisible($this->blockWaitElement); + $this->waitForElementVisible($this->discount, Locator::SELECTOR_CSS); $priceElement = $this->_rootElement->find($this->discount, Locator::SELECTOR_CSS); return $priceElement->isVisible() ? $this->escapeCurrency($priceElement->getText()) : null; } @@ -238,7 +240,7 @@ public function getShippingPriceInclTax() */ public function isVisibleShippingPriceBlock() { - return $this->_rootElement->find($this->shippingPriceBlockSelector, Locator::SELECTOR_CSS)->isVisible(); + return $this->_rootElement->find($this->shippingPriceBlockSelector, Locator::SELECTOR_CSS)->isVisible(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/AbstractReview.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/AbstractReview.php index 39804e9e0cbb5..c27a86f6f3aca 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/AbstractReview.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/AbstractReview.php @@ -1,6 +1,6 @@ _rootElement->find($this->updateButtonSelector)->click(); + } + + /** + * Set address value from dropdown. + * + * @param string $value + * @return void + */ + public function selectAddress($value) + { + $this->_rootElement->find($this->select, Locator::SELECTOR_CSS, 'select')->setValue($value); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Link.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Link.php index ee990ed0f2b63..5fcd6ccb4ea85 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Link.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Link.php @@ -1,6 +1,6 @@ waitForElementNotVisible($this->loadingMask); } + /** + * Fill required fields for guest checkout. + * + * @param Customer $customer + * @return void + */ + public function fillGuestFields(Customer $customer) + { + $mapping = $this->dataMapping(); + $this->_rootElement->find($mapping['email']['selector'], $mapping['email']['strategy']) + ->setValue($customer->getEmail()); + $this->waitForElementNotVisible($this->loadingMask); + } + /** * Click continue on checkout method block. * diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.xml index e22ff4c5ac826..7d9d3ac82276a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Login.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php index f1776d2bf933e..f9cf28e3f7f92 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment.php @@ -1,13 +1,12 @@ paymentMethodInput, $payment['method']); - $paymentLabelSelector = sprintf($this->paymentMethodLabel, $payment['method']); + public function selectPaymentMethod( + array $payment, + CreditCard $creditCard = null, + $fillCreditCardOn3rdParty = false + ) { + $paymentMethod = $payment['method']; + $paymentSelector = sprintf($this->paymentMethodInput, $paymentMethod); + $paymentLabelSelector = sprintf($this->paymentMethodLabel, $paymentMethod); try { + $this->waitForElementNotVisible($this->waitElement); $this->waitForElementVisible($paymentLabelSelector); } catch (\Exception $exception) { throw new \Exception('Such payment method is absent.'); } - + $browser = $this->browser; + $browser->waitUntil( + function () use ($browser, $paymentSelector) { + return $browser->find($paymentSelector); + } + ); $paymentRadioButton = $this->_rootElement->find($paymentSelector); if ($paymentRadioButton->isVisible()) { $paymentRadioButton->click(); } - if ($payment['method'] == "purchaseorder") { + if ($paymentMethod == "purchaseorder") { $this->_rootElement->find($this->purchaseOrderNumber)->setValue($payment['po_number']); } - if ($creditCard !== null) { - $class = explode('\\', get_class($creditCard)); - $module = $class[1]; - /** @var \Magento\Payment\Test\Block\Form\Cc $formBlock */ + if ($creditCard !== null && $fillCreditCardOn3rdParty === false) { + $module = $creditCard->hasData('payment_code') ? ucfirst($creditCard->getPaymentCode()) : 'Payment'; + /** @var \Magento\Payment\Test\Block\Form\PaymentCc $formBlock */ $formBlock = $this->blockFactory->create( - "\\Magento\\{$module}\\Test\\Block\\Form\\Cc", - ['element' => $this->_rootElement->find('#payment_form_' . $payment['method'])] + "\\Magento\\{$module}\\Test\\Block\\Form\\{$module}Cc", + ['element' => $this->_rootElement->find('#payment_form_' . $paymentMethod)] ); $formBlock->fill($creditCard); } } + /** + * Check visibility of payment method block by payment method type. + * + * @param array $payment + * @return bool + */ + public function isVisiblePaymentMethod(array $payment) + { + $paymentSelector = sprintf($this->paymentMethodInput, $payment['method']); + + return $this->_rootElement->find($paymentSelector)->isVisible(); + } + /** * Get selected payment method block. * diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/DiscountCodes.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/DiscountCodes.php index 88a6f45125a7b..bfc9988dfd060 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/DiscountCodes.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/DiscountCodes.php @@ -1,6 +1,6 @@ $element] ); } - - /** - * Save credit card. - * - * @param string $paymentMethod - * @param string $creditCardSave - * @return void - */ - public function saveCreditCard($paymentMethod, $creditCardSave) - { - $saveCard = sprintf($this->vaultCheckbox, $paymentMethod); - $this->_rootElement->find($saveCard, Locator::SELECTOR_CSS, 'checkbox')->setValue($creditCardSave); - } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.php index 167767e518a48..e2458eac1c834 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.php @@ -1,6 +1,6 @@ _rootElement->find($this->newAddressSelect, Locator::SELECTOR_CSS, 'select'); + if ($select && $select->isVisible()) { + $select->setValue($this->newAddressOption); + } $this->fill($billingAddress); $this->clickUpdate(); $this->waitForElementNotVisible($this->waitElement); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.xml index ff98767258f60..026f97e04a607 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Payment/Method/Billing.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php index e278ae040002b..49bad7d0801cf 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Registration.php @@ -1,6 +1,6 @@ _rootElement->find($this->emailError)->getText(); + } + + /** + * Get email tooltip. + * + * @return string + */ + public function getEmailTooltip() + { + $this->_rootElement->find($this->emailTooltipButton)->click(); + return $this->_rootElement->find($this->emailTooltipContent)->getText(); + } + + /** + * Get email instructions. + * + * @return string + */ + public function getEmailInstructions() + { + return $this->_rootElement->find($this->emailInstructions)->getText(); + } + + /** + * Click on "New Address" button. + * + * @return void + */ + public function clickOnNewAddressButton() + { + $this->waitForElementNotVisible($this->waitElement); + $this->_rootElement->find($this->newAddressButton)->click(); + } + + /** + * Get Address Modal Block. + * + * @return AddressModal + */ + public function getAddressModalBlock() + { + return $this->blockFactory->create( + AddressModal::class, + ['element' => $this->browser->find($this->addressModalBlock, Locator::SELECTOR_XPATH)] + ); + } + + /** + * Returns form's required elements + * + * @return \Magento\Mtf\Client\ElementInterface[] + */ + public function getRequiredFields() + { + return $this->_rootElement->getElements("div .field._required"); + } + + /** + * @return array + */ + public function getSelectedAddress() + { + return $this->_rootElement->find($this->selectedAddress, Locator::SELECTOR_CSS)->getText(); + } + + /** + * Select address. + * + * @param string $address + * @return void + */ + public function selectAddress($address) + { + $addresses = $this->_rootElement->getElements($this->shippingAddressBlock); + foreach ($addresses as $addressBlock) { + if (strpos($addressBlock->getText(), $address) === 0 && !$this->isAddressSelected($address)) { + $addressBlock->find($this->addressSelectButton)->click(); + break; + } + } + } + + /** + * Check if address selected. + * + * @param string $address + * @return bool + */ + public function isAddressSelected($address) + { + $text = $this->_rootElement->find($this->shippingAddressBlock . $this->selectedShippingAddressBlock)->getText(); + + return $text == $address; + } + + /** + * Checks if new address button is visible. + * + * @return bool + */ + public function isPopupNewAddressButtonVisible() + { + $button = $this->_rootElement->find($this->popupSelector); + return $button->isVisible(); + } + + /** + * Clicks new address button. + * + * @return void + */ + public function clickPopupNewAddressButton() + { + $this->_rootElement->find($this->popupSelector)->click(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml index fddef901bc0e1..666be65762b8e 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.php new file mode 100644 index 0000000000000..b62f4e4dd7952 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.php @@ -0,0 +1,84 @@ +_rootElement->find($this->saveButton)->click(); + } + + /** + * Get Error messages for attributes. + * + * @return array + */ + public function getErrorMessages() + { + $result = []; + foreach ($this->_rootElement->getElements($this->errorField) as $item) { + $result[$item->find($this->fieldLabel)->getText()] = $item->find($this->errorMessage)->getText(); + } + + return $result; + } + + /** + * Fixture mapping. + * + * @param array|null $fields + * @param string|null $parent + * @return array + */ + protected function dataMapping(array $fields = null, $parent = null) + { + if (isset($fields['custom_attribute'])) { + $this->placeholders = ['attribute_code' => $fields['custom_attribute']['code']]; + $this->applyPlaceholders(); + } + return parent::dataMapping($fields, $parent); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.xml new file mode 100644 index 0000000000000..fbae363e0f635 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/AddressModal.xml @@ -0,0 +1,29 @@ + + + + + + + + + input[name="street[0]"] + + + + select + + + select + + + + + [name="custom_attributes[%attribute_code%]"] + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php index d038ca0599d75..e59336171fd43 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping/Method.php @@ -1,6 +1,6 @@ waitForElementNotVisible($this->blockWaitElement); + } + + /** + * Retrieve if the shipping methods loader appears. + * + * @return bool|null + */ + public function isLoaderAppeared() + { + $this->_rootElement->click(); + return $this->waitForElementVisible($this->waitElement); + } + /** * Select shipping method. * @@ -50,15 +80,26 @@ class Method extends Block */ public function selectShippingMethod(array $method) { - // Code under test uses JavaScript setTimeout at this point as well. - sleep(3); + $this->waitForShippingRates(); $selector = sprintf($this->shippingMethod, $method['shipping_method'], $method['shipping_service']); - $this->waitForElementNotVisible($this->blockWaitElement); $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->click(); } /** - * Click continue button + * Check whether shipping method is available in the shipping rates. + * + * @param array $method + * @return bool + */ + public function isShippingMethodAvaiable(array $method) + { + $this->waitForShippingRates(); + $selector = sprintf($this->shippingMethod, $method['shipping_method'], $method['shipping_service']); + return $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->isVisible(); + } + + /** + * Click continue button. * * @return void */ @@ -74,4 +115,16 @@ function () use ($browser, $selector) { } ); } + + /** + * Get shipping method amount. + * + * @param array $method + * @return string + */ + public function getShippingMethodAmount(array $method) + { + $selector = sprintf($this->shippingMethodAmount, $method['shipping_method'], $method['shipping_service']); + return $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->getText(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.php new file mode 100644 index 0000000000000..b5f9a2155940d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.php @@ -0,0 +1,32 @@ +browser->find($this->saveAddressButton)->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.xml new file mode 100644 index 0000000000000..3c68025999548 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/ShippingPopup.xml @@ -0,0 +1,26 @@ + + + + + + + + + input[name="street[0]"] + + + + select + + + select + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Success.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Success.php index 42d20bcbe9cea..4c796cc1440a0 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Success.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Success.php @@ -1,6 +1,6 @@ open(); + $categoryName = $category === null ? $product->getCategoryIds()[0] : $category->getName(); + $cmsIndex->getTopmenu()->selectCategoryByName($categoryName); + + $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); + while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { + $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); + } + \PHPUnit_Framework_Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); + + \PHPUnit_Framework_Assert::assertFalse( + $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisibleAddToCardButton(), + 'Button "Add to Cart" is present on category page.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Button "Add to Cart" is absent on product page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnProductPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnProductPage.php new file mode 100644 index 0000000000000..a788dc3a27b29 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnProductPage.php @@ -0,0 +1,48 @@ +open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + \PHPUnit_Framework_Assert::assertFalse( + $catalogProductView->getViewBlock()->isVisibleAddToCardButton(), + 'Button "Add to Cart" is present on product page.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Button "Add to Cart" is absent on product page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnCategoryPage.php new file mode 100644 index 0000000000000..c7a8ac4d95082 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnCategoryPage.php @@ -0,0 +1,60 @@ +open(); + $categoryName = $category === null ? $product->getCategoryIds()[0] : $category->getName(); + $cmsIndex->getTopmenu()->selectCategoryByName($categoryName); + + $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); + while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { + $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); + } + \PHPUnit_Framework_Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); + + \PHPUnit_Framework_Assert::assertTrue( + $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisibleAddToCardButton(), + 'Button "Add to Cart" is absent on category page.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Button "Add to Cart" is present on category page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnProductPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnProductPage.php new file mode 100644 index 0000000000000..4c32c06d15d91 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnProductPage.php @@ -0,0 +1,48 @@ +open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + \PHPUnit_Framework_Assert::assertTrue( + $catalogProductView->getViewBlock()->isVisibleAddToCardButton(), + 'Button "Add to Cart" is absent on product page.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Button "Add to Cart" is present on product page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php index 96f73e9bd8012..ad329eda4f69d 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php @@ -1,6 +1,6 @@ getPaymentBlock() + ->getSelectedPaymentMethodBlock() + ->getBillingBlock() + ->isVisible(), + 'Billing address is present in payment method' + ); + } + + /** + * Returns string representation of successful assertion + * + * @return string + */ + public function toString() + { + return 'Billing address is absent in payment method'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php index 282e3c02e34db..5291adbfc3aa9 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php @@ -1,6 +1,6 @@ getMessagesBlock()->getSuccessMessage(); + \PHPUnit_Framework_Assert::assertEquals( + self::SUCCESS_MESSAGE, + $actualMessage, + 'Success message is not present or has wrong text.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Cancel success message is present or has a correct text.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php index 300c84c4c2ad3..12b7b0a520342 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php @@ -1,6 +1,6 @@ $customer) { + if (!empty($cartFixtures[$index])) { + $stepFactory->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $customer] + )->run(); + \PHPUnit_Framework_Assert::assertEquals( + sprintf(self::WELCOME_MESSAGE, $customer->getFirstname()), + $cmsIndex->getLinksBlock()->getWelcomeText(), + 'Customer welcome message is wrong.' + ); + $assertProductQty->processAssert($checkoutCart, $cartFixtures[$index]); + $assertSubtotal->processAssert($checkoutCart, $cartFixtures[$index]); + $assertGrandtotal->processAssert($checkoutCart, $cartFixtures[$index]); + $assertMinicart->processAssert($cmsIndex, $cartFixtures[$index]); + } + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Shopping cart data is correct for each customer.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php new file mode 100644 index 0000000000000..fb2f9022b9835 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php @@ -0,0 +1,42 @@ +getMessagesBlock()->getErrorMessage(), + 'Wrong error message is displayed.' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Error message on Checkout onepage page is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php new file mode 100644 index 0000000000000..28c01a6f7e13d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php @@ -0,0 +1,115 @@ +stepFactory = $stepFactory; + + $miniShoppingCart = $cmsIndex->getCartSidebarBlock(); + $miniShoppingCart->openMiniCart(); + $miniShoppingCart->clickProceedToCheckoutButton(); + + \PHPUnit_Framework_Assert::assertTrue( + !$checkoutOnepage->getMessagesBlock()->isVisible() + && $checkoutOnepage->getShippingMethodBlock()->isVisible(), + 'Checkout first step is not available.' + ); + + if (isset($checkoutData['shippingAddress'])) { + $this->getOrder($checkoutData); + } + + //Assert that Order Grand Total is correct on order page in backend. + $assertOrderGrandTotal->processAssert($salesOrderView, $orderIndex, $this->orderId, $prices); + } + + /** + * Get Order. + * + * @param array $checkoutData + * @return void + */ + protected function getOrder(array $checkoutData) + { + $this->stepFactory->create( + \Magento\Checkout\Test\TestStep\FillShippingAddressStep::class, + ['shippingAddress' => $checkoutData['shippingAddress']] + )->run(); + $this->objectManager->create( + \Magento\Checkout\Test\TestStep\FillShippingMethodStep::class, + ['shipping' => $checkoutData['shipping']] + )->run(); + $this->objectManager->create( + \Magento\Checkout\Test\TestStep\SelectPaymentMethodStep::class, + ['payment' => $checkoutData['payment']] + )->run(); + $this->orderId = $this->objectManager->create( + \Magento\Checkout\Test\TestStep\PlaceOrderStep::class + )->run()['orderId']; + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Checkout first step is available.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php index 1b2c11f8a6b09..468ecc2395ef6 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php @@ -1,6 +1,6 @@ getShippingBlock()->getEmailError(), + 'Email validation message is not correct.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Email validation message is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailToolTips.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailToolTips.php new file mode 100644 index 0000000000000..19276c380dbbc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailToolTips.php @@ -0,0 +1,58 @@ +getShippingBlock()->getEmailTooltip(), + 'Email tooltip is not correct.' + ); + + \PHPUnit_Framework_Assert::assertEquals( + self::EMAIL_INSTRUCTIONS, + $checkoutOnepage->getShippingBlock()->getEmailInstructions(), + 'Email instructions are not correct.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Email field tooltips are present.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEstimateShippingAndTax.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEstimateShippingAndTax.php index db02552b80d68..698430eff663b 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEstimateShippingAndTax.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEstimateShippingAndTax.php @@ -1,6 +1,6 @@ getReviewBlock()->waitForElementNotVisible($this->waitElement); $checkoutReviewGrandTotal = $checkoutOnepage->getReviewBlock()->getGrandTotal(); \PHPUnit_Framework_Assert::assertEquals( diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php index 1b860949698ec..64fbe2eb180df 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php @@ -1,6 +1,6 @@ open(); + \PHPUnit_Framework_Assert::assertSame( + (int)$expectedItemsQty, + $cmsIndex->getCartSidebarBlock()->getItemsQty(), + 'The quantity of items in shopping cart is not correct.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'The quantity of items in mini shopping cart is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMyCartLinkRedirect.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMyCartLinkRedirect.php new file mode 100644 index 0000000000000..7bdccfd51e4f2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMyCartLinkRedirect.php @@ -0,0 +1,48 @@ +open(); + $cmsIndex->getCartSidebarBlock()->openMiniCart(); + \PHPUnit_Framework_Assert::assertEquals( + self::CART_PAGE_TITLE, + $cmsIndex->getTitleBlock()->getTitle(), + 'Wrong page is displayed instead of the shopping cart page.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'My Cart link redirects to the shopping cart page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php index 9aaa0e06843ba..54e5500e5d630 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php @@ -1,6 +1,6 @@ getPaymentBlock()->isVisiblePaymentMethod($payment), + 'Payment method' . $payment['method']. ' is present on Checkout Payment Page.' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Payment method is absent on Checkout Payment Page'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php index a24c7adf89b03..5ac812dcaeabb 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php @@ -1,6 +1,6 @@ getShippingBlock()->getRequiredFields(); + + /** @var \Magento\Mtf\Client\ElementInterface $field */ + foreach ($requiredFields as $field) { + $errorContainer = $field->find("div .field-error"); + \PHPUnit_Framework_Assert::assertFalse( + $errorContainer->isVisible(), + 'Js validation error messages must be absent for required fields after checkout start.' + ); + } + } + + /** + * Returns string representation of successful assertion + * + * @return string + */ + public function toString() + { + return 'Js validation messages are absent for required fields.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php index c2fc04ff1ce6f..7f4aec57f1146 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php @@ -1,6 +1,6 @@ open(); + \PHPUnit_Framework_Assert::assertEquals( + $topDestinations, + $checkoutCart->getShippingBlock()->getTopCountries(), + 'Top countries are different from the ones selected as Top Destinations.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Countries selected as Top Destinations are at the top in select.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml index 04b191b2b6583..172466cb4d46a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart.xml @@ -1,7 +1,7 @@ @@ -10,7 +10,6 @@ module="Magento_Checkout" type="flat" entity_type="quote" - repository_class="Magento\Checkout\Test\Repository\Cart" handler_interface="Magento\Checkout\Test\Handler\Cart\CartInterface" class="Magento\Checkout\Test\Fixture\Cart"> diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart/Items.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart/Items.php index 6b270efcb011e..a5c9499e2b792 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart/Items.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Fixture/Cart/Items.php @@ -1,6 +1,6 @@ params = $params; $this->products = isset($data['products']) ? $data['products'] : []; - - foreach ($this->products as $product) { - $classItem = 'Magento\\' . $this->getModuleName($product) . '\Test\Fixture\Cart\Item'; - $item = ObjectManager::getInstance()->create($classItem, ['product' => $product]); - - $this->data[] = $item; - } } /** @@ -55,6 +48,24 @@ protected function getModuleName(FixtureInterface $product) return isset($match[1]) ? $match[1] : ''; } + /** + * Return prepared dataset. + * + * @param null|string $key + * @return array + */ + public function getData($key = null) + { + foreach ($this->products as $product) { + $classItem = 'Magento\\' . $this->getModuleName($product) . '\Test\Fixture\Cart\Item'; + $item = ObjectManager::getInstance()->create($classItem, ['product' => $product]); + $item->getData(); + $this->data[] = $item; + } + + return parent::getData($key); + } + /** * Get source products. * diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutCart.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutCart.xml index 06ecb57969e54..5afe8e14b638b 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutCart.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutCart.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml index f8dcf95b0c16d..d30b0328bb7d9 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepage.xml @@ -1,19 +1,23 @@ + + + - + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepageSuccess.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepageSuccess.xml index 561b5d7123ca9..a45aa28713ef9 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepageSuccess.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CheckoutOnepageSuccess.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CmsIndex.xml index 9134f40956f2d..0c1fbba666f22 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CmsIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Page/CmsIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Repository/ConfigData.xml new file mode 100644 index 0000000000000..a4fe878794f4b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Repository/ConfigData.xml @@ -0,0 +1,64 @@ + + + + + + + checkout + 1 + No + 0 + + + + + + checkout + 1 + Yes + 1 + + + + + + customer + 1 + No + 0 + + + + + + customer + 1 + Yes + 1 + + + + + + checkout + 1 + No + 0 + + + + + + checkout + 1 + Yes + 1 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.php index 0733d778b9662..b94fe00e385cd 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.php @@ -1,6 +1,6 @@ browser = $browser; $this->fixtureFactory = $fixtureFactory; $this->catalogProductView = $catalogProductView; $this->cartPage = $cartPage; + $this->testStepFactory = $testStepFactory; + $this->cache = $cache; } /** - * Run test add products to shopping cart + * Run test add products to shopping cart. * * @param array $productsData * @param array $cart + * @param string|null $configData [optional] + * @param bool $flushCache [optional] * @return array */ - public function test(array $productsData, array $cart) + public function test(array $productsData, array $cart, $configData = null, $flushCache = false) { // Preconditions + $this->configData = $configData; + $this->flushCache = $flushCache; + + $this->testStepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'flushCache' => $this->flushCache] + )->run(); + + if ($this->configData == 'enable_https_frontend_admin_with_url') { + $_ENV['app_backend_url'] = preg_replace('/(http[s]?)/', 'https', $_ENV['app_backend_url']); + $_ENV['app_frontend_url'] = preg_replace('/(http[s]?)/', 'https', $_ENV['app_frontend_url']); + } $products = $this->prepareProducts($productsData); // Steps @@ -101,14 +160,14 @@ public function test(array $productsData, array $cart) } /** - * Create products + * Create products. * * @param array $productList * @return array */ protected function prepareProducts(array $productList) { - $addToCartStep = ObjectManager::getInstance()->create( + $addToCartStep = $this->testStepFactory->create( \Magento\Catalog\Test\TestStep\CreateProductsStep::class, ['products' => $productList] ); @@ -118,17 +177,70 @@ protected function prepareProducts(array $productList) } /** - * Add products to cart + * Add products to cart. * * @param array $products * @return void */ protected function addToCart(array $products) { - $addToCartStep = ObjectManager::getInstance()->create( + $addToCartStep = $this->testStepFactory->create( \Magento\Checkout\Test\TestStep\AddProductsToTheCartStep::class, ['products' => $products] ); $addToCartStep->run(); } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + // Workaround until MTA-3879 is delivered. + if ($this->configData == 'enable_https_frontend_admin_with_url') { + $this->getSystemConfigEditPage()->open(); + $this->getSystemConfigEditPage()->getForm() + ->getGroup('web', 'secure')->setValue('web', 'secure', 'use_in_frontend', 'No'); + $this->getSystemConfigEditPage()->getForm() + ->getGroup('web', 'secure')->setValue('web', 'secure', 'use_in_adminhtml', 'No'); + $this->getSystemConfigEditPage()->getForm() + ->getGroup('web', 'secure')->setValue('web', 'secure', 'base_url', $this->getBaseUrl()); + $this->getSystemConfigEditPage()->getForm() + ->getGroup('web', 'secure')->setValue('web', 'secure', 'base_link_url', $this->getBaseUrl()); + $this->getSystemConfigEditPage()->getPageActions()->save(); + $_ENV['app_backend_url'] = preg_replace('/(http[s]?)/', 'http', $_ENV['app_backend_url']); + $_ENV['app_frontend_url'] = preg_replace('/(http[s]?)/', 'http', $_ENV['app_frontend_url']); + $this->cache->flush(); + } + } + + /** + * Get base URL. + * + * @param bool $useHttps + * @return string + */ + private function getBaseUrl($useHttps = false) + { + $protocol = $useHttps ? 'https' : 'http'; + return preg_replace('/(http[s]?)/', $protocol, $_ENV['app_frontend_url']); + } + + /** + * Create System Config Edit Page. + * + * @return SystemConfigEdit + */ + private function getSystemConfigEditPage() + { + if (null === $this->configurationAdminPage) { + $this->configurationAdminPage = \Magento\Mtf\ObjectManagerFactory::getObjectManager()->create( + \Magento\Backend\Test\Page\Adminhtml\SystemConfigEdit::class + ); + } + + return $this->configurationAdminPage; + } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml index f64258b1de297..49765abc50f53 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml @@ -1,16 +1,18 @@ - + + severity:S2 bundleProduct::bundle_dynamic_product 210 200 + 2 @@ -18,8 +20,10 @@ + + to_maintain:yes, severity:S2 bundleProduct::bundle_fixed_product 761 756 @@ -32,6 +36,7 @@ + to_maintain:yes, severity:S0 catalogProductSimple::with_two_custom_option 345 340 @@ -44,6 +49,7 @@ + to_maintain:yes, severity:S1 catalogProductVirtual::product_50_dollar 50 50 @@ -56,6 +62,7 @@ + to_maintain:yes, severity:S0 configurableProduct::default 135 120 @@ -68,6 +75,7 @@ + severity:S2 downloadableProduct::with_two_separately_links 22.43 22.43 @@ -80,6 +88,7 @@ + to_maintain:yes, severity:S2 groupedProduct::three_simple_products 1950 1920 @@ -91,7 +100,8 @@ - + + severity:S0 catalogProductSimple::with_two_custom_option catalogProductVirtual::product_50_dollar downloadableProduct::with_two_separately_links @@ -99,8 +109,12 @@ configurableProduct::default bundleProduct::bundle_fixed_product bundleProduct::bundle_dynamic_product - 2922.43 - 2852.43 + 3473.43 + 3408.43 + enable_https_frontend_admin_with_url + true + 15 + @@ -108,5 +122,31 @@ + + disable_display_shopping_cart_sidebar + true + bundleProduct::bundle_dynamic_product + 210 + 200 + + + + + + + + + catalogProductSimple::product_10_dollar + top_destinations_DE_ES_GB + 15.00 + 10.00 + + DE + ES + GB + + MAGETWO-61592 - [Shopping Cart] Top destinations are not displayed in the shopping cart summary + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductFromMiniShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductFromMiniShoppingCartTest.php index f2a809656ed65..e36053c136c85 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductFromMiniShoppingCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductFromMiniShoppingCartTest.php @@ -1,6 +1,6 @@ + severity:S0 delete Simple catalogProductSimple::default catalogProductVirtual::default @@ -16,6 +17,7 @@ + severity:S1 delete Simple catalogProductSimple::default 0 diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductsFromShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductsFromShoppingCartTest.php index ae48e6e6b7948..f73be1596cc58 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductsFromShoppingCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/DeleteProductsFromShoppingCartTest.php @@ -1,6 +1,6 @@ + severity:S2 bundleProduct::bundle_dynamic_product + severity:S2 bundleProduct::bundle_fixed_product + to_maintain:yes, severity:S1 catalogProductSimple::with_two_custom_option + severity:S2 catalogProductVirtual::product_50_dollar + severity:S1 configurableProduct::default + severity:S2 downloadableProduct::with_two_separately_links + severity:S2 groupedProduct::three_simple_products + to_maintain:yes, severity:S1 catalogProductSimple::with_two_custom_option catalogProductVirtual::product_50_dollar downloadableProduct::with_two_separately_links diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutDeclinedTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutDeclinedTest.php new file mode 100644 index 0000000000000..b1d56738a52a3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutDeclinedTest.php @@ -0,0 +1,46 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutFromMiniShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutFromMiniShoppingCartTest.php new file mode 100644 index 0000000000000..f8475988ae5e8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutFromMiniShoppingCartTest.php @@ -0,0 +1,51 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.php new file mode 100644 index 0000000000000..5ab1f389d6588 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.php @@ -0,0 +1,37 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.xml new file mode 100644 index 0000000000000..adae8d94c4b4c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutJsValidationTest.xml @@ -0,0 +1,17 @@ + + + + + + severity:S2 + catalogProductSimple::default + guest + + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.php index 58d0c23f2274f..2de602432cfad 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.php @@ -1,6 +1,6 @@ + + severity:S1 + catalogProductSimple::default + johndoe_with_addresses + login + + 565.00 + + Flat Rate + Fixed + checkmo + checkmo, disable_guest_checkout, disable_customer_redirect_after_logging + + + + MAGETWO-59816: Redirect works improperly in a browser incognito mode + severity:S1 + catalogProductSimple::default + register_customer + register_before_checkout + + 565.00 + + Flat Rate + Fixed + US_address_1_without_email + checkmo + checkmo, disable_guest_checkout, disable_customer_redirect_after_logging, enable_https_frontend_only + + + severity:S0 catalogProductVirtual::default downloadableProduct::with_two_separately_links active_sales_rule_for_all_groups @@ -27,6 +58,7 @@ + stable:no, severity:S0 catalogProductSimple::default active_sales_rule_for_all_groups default @@ -47,28 +79,33 @@ - - catalogProductSimple::default + + severity:S1 + catalogProductSimple::product_with_qty_25 + 0 + out of stock default guest UK_address Flat Rate Fixed - 565.00 + 375.00 banktransfer Pending Back, Send Email, Cancel, Hold, Ship, Invoice, Edit - banktransfer_specificcountry_gb + banktransfer_specificcountry_gb, can_subtract_and_can_back_in_stock + + - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, severity:S0 catalogProductSimple::product_with_special_price configurableProduct::product_with_special_price default @@ -90,7 +127,7 @@ - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, stable:no, severity:S0 catalogProductSimple::product_10_dollar configurableProduct::with_one_option bundleProduct::bundle_fixed_100_dollar_product @@ -114,10 +151,11 @@ + severity:S0 catalogProductVirtual::product_50_dollar active_sales_rule_with_fixed_price_discount_coupon default - UK_address + UK_address_without_email guest 0.00 @@ -133,9 +171,10 @@ + severity:S1 catalogProductSimple::product_with_qty_25 guest - UK_address + UK_address_without_email Flat Rate Fixed @@ -152,6 +191,7 @@ + severity:S0 catalogProductSimple::default default register @@ -166,11 +206,13 @@ - + + stable:no, severity:S1 catalogProductSimple::simple_with_tier_price_and_order_qty_3 default - guest - UK_address + login + UK_address_without_email + UK_address_2_without_email Flat Rate Fixed @@ -180,9 +222,11 @@ banktransfer_specificcountry_gb + - + + severity:S0 catalogProductVirtual::default downloadableProduct::with_two_separately_links configurableProduct::with_one_option @@ -191,7 +235,7 @@ groupedProduct::three_simple_products default login - UK_address_without_email + UK_address_without_email_first_name_last_name Flat Rate Fixed @@ -199,7 +243,92 @@ checkmo checkmo + + + + + severity:S1 + catalogProductSimple::default + customer_UK_US_addresses + sign_in + + 1 + + + 1 + + + 565.00 + + Flat Rate + Fixed + checkmo + checkmo + + + + + severity:S1 + catalogProductSimple::default + customer_US_DE_UK + login + + 1 + + + 2 + + + 565.00 + + Flat Rate + Fixed + checkmo + checkmo + + + + + + severity:S1 + catalogProductSimple::default + johndoe_with_addresses + sign_in + + 565.00 + + UK_address_without_email + Flat Rate + Fixed + Yes + US_address_1_without_email + checkmo + checkmo + + + + + + severity:S1 + catalogProductSimple::default + customer_UK_US_addresses + login + + 0 + + + 0 + + + 565.00 + + Flat Rate + Fixed + checkmo + checkmo_specificcountry_gb + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ShoppingCartPerCustomerTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ShoppingCartPerCustomerTest.php new file mode 100644 index 0000000000000..762fecc086954 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ShoppingCartPerCustomerTest.php @@ -0,0 +1,169 @@ +checkoutCart = $checkoutCart; + $this->fixtureFactory = $fixtureFactory; + $this->cache = $cache; + } + + /** + * Run test for shopping cart with different customers. + * + * @param array $productsData + * @param string $customerDataset + * @param array $checkoutData + * @return array + */ + public function test( + array $productsData, + $customerDataset, + array $checkoutData + ) { + //Preconditions + $this->cache->flush(); + $products = $this->objectManager->create( + \Magento\Catalog\Test\TestStep\CreateProductsStep::class, + ['products' => $productsData] + )->run()['products']; + + $customers = []; + $cartFixtures = []; + for ($i = 0; $i < count($checkoutData); $i++) { + $customers[$i] = $this->fixtureFactory->createByCode('customer', ['dataset' => $customerDataset]); + $customers[$i]->persist(); + + if (isset($checkoutData[$i])) { + $cartFixtures[$i] = $this->prepareShoppingCart($customers[$i], $checkoutData[$i], $products); + } + } + + //Steps + if (!empty($customers[0])) { + $this->objectManager->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $customers[0]] + )->run(); + $this->checkoutCart->open(); + $this->checkoutCart->open(); + } + + return [ + 'customers' => $customers, + 'cartFixtures' => $cartFixtures, + ]; + } + + /** + * Prepare shopping cart for customer. + * + * @param Customer $customer + * @param array $checkoutData + * @param array $products + * @return \Magento\Checkout\Test\Fixture\Cart|null + */ + private function prepareShoppingCart(Customer $customer, array $checkoutData, array $products) + { + $productsInCart = []; + if (isset($checkoutData['items'])) { + foreach ($checkoutData['items'] as $index => $dataset) { + if (isset($products[$index])) { + $productFixture = $this->fixtureFactory->create( + get_class($products[$index]), + [ + 'data' => array_merge( + $products[$index]->getData(), + ['checkout_data' => ['dataset' => $dataset]] + ) + ] + ); + $productsInCart[] = $productFixture; + } + } + } + + if (!empty($productsInCart)) { + $this->objectManager->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $customer] + )->run(); + + $this->objectManager->create( + \Magento\Checkout\Test\TestStep\AddProductsToTheCartStep::class, + ['products' => $productsInCart] + )->run(); + + $cart['data'] = isset($checkoutData['totals']) ? $checkoutData['totals'] : []; + $cart['data']['items'] = ['products' => $productsInCart]; + return $this->fixtureFactory->createByCode('cart', $cart); + } + + return null; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ShoppingCartPerCustomerTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ShoppingCartPerCustomerTest.xml new file mode 100644 index 0000000000000..2a1954fda1bba --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ShoppingCartPerCustomerTest.xml @@ -0,0 +1,38 @@ + + + + + + catalogProductSimple::default + catalogProductSimple::with_two_custom_option + johndoe_unique_firstname + + + + simple_order_default + simple_with_two_custom_option + + + 900.00 + 910.00 + + + + + simple_with_two_custom_option_qty_2 + + + 740.00 + 750.00 + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php index 62d773a6637bf..b12c76db368a6 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.php @@ -1,6 +1,6 @@ persist(); + } $product = $this->createProduct($originalProduct); $this->addToCart($product); @@ -93,16 +109,25 @@ public function test(array $originalProduct, array $checkoutData) $newProduct = $this->createProduct([explode('::', $originalProduct[0])[0]], [$productData]); $miniShoppingCart = $this->cmsIndex->getCartSidebarBlock(); $miniShoppingCart->openMiniCart(); - $miniShoppingCart->getCartItem($newProduct)->clickEditItem(); - $this->catalogProductView->getViewBlock()->addToCart($newProduct); + if ($useMiniCartToEditQty) { + $miniShoppingCart->getCartItem($newProduct)->editQty($newProduct->getCheckoutData()); + } else { + $miniShoppingCart->getCartItem($newProduct)->clickEditItem(); + $this->catalogProductView->getViewBlock()->addToCart($newProduct); + } // Prepare data for asserts: $cart['data']['items'] = ['products' => [$newProduct]]; $deletedCart['data']['items'] = ['products' => [$product]]; return [ 'deletedCart' => $this->fixtureFactory->createByCode('cart', $deletedCart), - 'cart' => $this->fixtureFactory->createByCode('cart', $cart) + 'cart' => $this->fixtureFactory->createByCode('cart', $cart), + 'checkoutData' => [ + 'shippingAddress' => $shippingAddress, + 'shipping' => $shipping, + 'payment' => $payment + ] ]; } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml index 1c60b0f156bae..95b91ce10ff15 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml @@ -1,21 +1,31 @@ - - test_type:extended_acceptance_test - catalogProductSimple::with_two_custom_option - simple_update_mini_shopping_cart + + test_type:extended_acceptance_test, severity:S0 + catalogProductSimple::default + simple_order_qty_2 + true + + 1130 + + customer_US + Flat Rate + Fixed + UK_address + free + - test_type:extended_acceptance_test + test_type:extended_acceptance_test, to_maintain:yes, severity:S0 configurableProduct::default configurable_update_mini_shopping_cart @@ -24,7 +34,7 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, to_maintain:yes, severity:S0 bundleProduct::bundle_fixed_product bundle_update_mini_shopping_cart @@ -33,7 +43,7 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, to_maintain:yes, severity:S1 downloadableProduct::with_two_separately_links downloadable_update_mini_shopping_cart @@ -42,7 +52,7 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, to_maintain:yes, severity:S1 catalogProductVirtual::default virtual_update_mini_shopping_cart diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php index 809688cd8286a..f5c6b6584c323 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.php @@ -1,6 +1,6 @@ + severity:S0 default 100 3 @@ -19,6 +20,7 @@ + severity:S0 with_two_custom_option 50 11 diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.php new file mode 100644 index 0000000000000..343a94a353362 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.php @@ -0,0 +1,74 @@ +persist(); + + $cartPage->open(); + $cartPage->getCartBlock()->clearShoppingCart(); + + //Steps + $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $productView = $catalogProductView->getViewBlock(); + $productView->fillOptions($product); + $productView->setQty($product->getCheckoutData()['qty']); + $productView->clickAddToCart(); + $catalogProductView->getMessagesBlock()->waitSuccessMessage(); + + $checkoutOnepage->open(); + $checkoutOnepage->getShippingBlock()->fill($customer); + $checkoutOnepage->getShippingMethodBlock()->clickContinue(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.xml new file mode 100644 index 0000000000000..c6928228fa2e0 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.xml @@ -0,0 +1,27 @@ + + + + + + johndoe + John + + + + + johndoe#example.com + John + + + + johndoe@example.c + John + + + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/VerifyPaymentMethodOnCheckoutTest.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/VerifyPaymentMethodOnCheckoutTest.php new file mode 100644 index 0000000000000..480c511db57c1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/VerifyPaymentMethodOnCheckoutTest.php @@ -0,0 +1,46 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddNewShippingAddressStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddNewShippingAddressStep.php new file mode 100644 index 0000000000000..57852414d179d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddNewShippingAddressStep.php @@ -0,0 +1,57 @@ +checkoutOnepage = $checkoutOnepage; + $this->address = $address; + } + + /** + * Create customer account. + * + * @return void + */ + public function run() + { + $shippingBlock = $this->checkoutOnepage->getShippingBlock(); + $shippingBlock->clickOnNewAddressButton(); + if ($this->address) { + $shippingBlock->getAddressModalBlock()->fill($this->address); + } + $shippingBlock->getAddressModalBlock()->save(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php index 37df8ea8b8925..1e7640bcaf8c7 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/AddProductsToTheCartStep.php @@ -1,6 +1,6 @@ products = $products; $this->catalogProductView = $catalogProductView; $this->checkoutCart = $checkoutCart; $this->cmsIndex = $cmsIndex; $this->browser = $browser; + $this->fixtureFactory = $fixtureFactory; + $this->products = $products; } /** - * Add products to the cart + * Add products to the cart. * - * @return void + * @return array */ public function run() { @@ -89,5 +99,7 @@ public function run() $this->catalogProductView->getViewBlock()->addToCart($product); $this->catalogProductView->getMessagesBlock()->waitSuccessMessage(); } + $cart['data']['items'] = ['products' => $this->products]; + return ['cart' => $this->fixtureFactory->createByCode('cart', $cart)]; } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickPlaceOrderButtonStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickPlaceOrderButtonStep.php new file mode 100644 index 0000000000000..0811a4cfe0e87 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickPlaceOrderButtonStep.php @@ -0,0 +1,41 @@ +checkoutOnepage = $checkoutOnepage; + } + + /** + * Click 'Place order' button. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickProceedToCheckoutStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickProceedToCheckoutStep.php index 32b2152cb8240..f2a692319a78f 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickProceedToCheckoutStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ClickProceedToCheckoutStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; $this->billingAddress = $billingAddress; $this->shippingAddress = $shippingAddress; $this->assertBillingAddressCheckbox = $assertBillingAddressCheckbox; + $this->customer = $customer; + $this->objectManager = $objectManager; $this->billingCheckboxState = $billingCheckboxState; + $this->billingAddressCustomer = $billingAddressCustomer; } /** * Fill billing address. * - * @return void + * @return array */ public function run() { + $billingAddress = $this->billingAddress; if ($this->billingCheckboxState) { $this->assertBillingAddressCheckbox->processAssert($this->checkoutOnepage, $this->billingCheckboxState); } - if ($this->billingAddress) { $selectedPaymentMethod = $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock(); if ($this->shippingAddress) { $selectedPaymentMethod->getBillingBlock()->unsetSameAsShippingCheckboxValue(); } $selectedPaymentMethod->getBillingBlock()->fillBilling($this->billingAddress); + $billingAddress = $this->billingAddress; + } + if (isset($this->billingAddressCustomer['added'])) { + $addressIndex = $this->billingAddressCustomer['added']; + $billingAddress = $this->customer->getDataFieldConfig('address')['source']->getAddresses()[$addressIndex]; + $address = $this->objectManager->create( + \Magento\Customer\Test\Block\Address\Renderer::class, + ['address' => $billingAddress, 'type' => 'html_for_select_element'] + )->render(); + $selectedPaymentMethod = $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock(); + $selectedPaymentMethod->getBillingBlock()->unsetSameAsShippingCheckboxValue(); + $this->checkoutOnepage->getCustomAddressBlock()->selectAddress($address); + $selectedPaymentMethod->getBillingBlock()->clickUpdate(); } + + return [ + 'billingAddress' => $billingAddress + ]; } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingAddressStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingAddressStep.php index 5150eb9964ba3..3562c3b66e0ee 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingAddressStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingAddressStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; + $this->customer = $customer; + $this->objectManager = $objectManager; + $this->fixtureFactory = $fixtureFactory; $this->shippingAddress = $shippingAddress; + $this->shippingAddressCustomer = $shippingAddressCustomer; } /** * Fill shipping address. * - * @return void + * @return array */ public function run() { + $shippingAddress = null; if ($this->shippingAddress) { - $this->checkoutOnepage->getShippingBlock()->fill($this->shippingAddress); + $shippingBlock = $this->checkoutOnepage->getShippingBlock(); + if ($shippingBlock->isPopupNewAddressButtonVisible()) { + $shippingBlock->clickPopupNewAddressButton(); + $this->checkoutOnepage->getShippingAddressPopupBlock() + ->fill($this->shippingAddress) + ->clickSaveAddressButton(); + } else { + $shippingBlock->fill($this->shippingAddress); + } + $shippingAddress = $this->shippingAddress; + } + if (isset($this->shippingAddressCustomer['new'])) { + $shippingAddress = $this->fixtureFactory->create( + 'address', + ['dataset' => $this->shippingAddressCustomer['new']] + ); + $this->checkoutOnepage->getShippingBlock()->clickPopupNewAddressButton(); + $this->checkoutOnepage->getShippingAddressPopupBlock()->fill($shippingAddress)->clickSaveAddressButton(); } + if (isset($this->shippingAddressCustomer['added'])) { + $addressIndex = $this->shippingAddressCustomer['added']; + $shippingAddress = $this->customer->getDataFieldConfig('address')['source']->getAddresses()[$addressIndex]; + $address = $this->objectManager->create( + \Magento\Customer\Test\Block\Address\Renderer::class, + ['address' => $shippingAddress, 'type' => 'html_without_company'] + )->render(); + $shippingBlock = $this->checkoutOnepage->getShippingBlock(); + $shippingBlock->selectAddress($address); + } + + return [ + 'shippingAddress' => $shippingAddress, + ]; } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingMethodStep.php index afd0550cf3e99..34cda4558753a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillShippingMethodStep.php @@ -1,6 +1,6 @@ checkoutOnepageSuccess = $checkoutOnepageSuccess; + $this->decorator = $decorator; + } + + /** + * Get success placed order id. + * + * @return array + */ + public function run() + { + $incrementId = $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(); + return [ + 'entityId' => $this->getEntityId($incrementId), + 'orderId' => $incrementId + ]; + } + + /** + * Get order entity id by increment id. + * + * @param string $incrementId + * @return string + */ + private function getEntityId($incrementId) + { + $url = $_ENV['app_frontend_url'] . 'rest/V1/orders/'; + $url .= '?searchCriteria[filterGroups][0][filters][0][field]=increment_id'; + $url .= '&searchCriteria[filterGroups][0][filters][0][value]=' . $incrementId; + $this->decorator->write($url, [], WebapiDecorator::GET); + $response = json_decode($this->decorator->read(), true); + $this->decorator->close(); + return $response['items'][0]['entity_id']; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php index 2bfd346fbcaeb..88466249ba2e8 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/PlaceOrderStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; $this->assertGrandTotalOrderReview = $assertGrandTotalOrderReview; - $this->prices = $prices; $this->checkoutOnepageSuccess = $checkoutOnepageSuccess; $this->fixtureFactory = $fixtureFactory; $this->products = $products; + $this->prices = $prices; + $this->order = $order; } /** @@ -91,18 +105,20 @@ public function run() $this->assertGrandTotalOrderReview->processAssert($this->checkoutOnepage, $this->prices['grandTotal']); } $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $orderId = $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(); + $data = [ + 'id' => $orderId, + 'entity_id' => ['products' => $this->products] + ]; + $orderData = $this->order !== null ? $this->order->getData() : []; $order = $this->fixtureFactory->createByCode( 'orderInjectable', - [ - 'data' => [ - 'entity_id' => ['products' => $this->products] - ] - ] + ['data' => array_merge($data, $orderData)] ); return [ - 'orderId' => $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(), - 'order' => $order + 'orderId' => $orderId, + 'order' => $order, ]; } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ProceedToCheckoutFromMiniShoppingCartStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ProceedToCheckoutFromMiniShoppingCartStep.php new file mode 100644 index 0000000000000..b625c05faee15 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ProceedToCheckoutFromMiniShoppingCartStep.php @@ -0,0 +1,42 @@ +miniShoppingCart = $cmsIndex->getCartSidebarBlock(); + } + + /** + * Proceed to checkout. + * + * @return void + */ + public function run() + { + $this->miniShoppingCart->openMiniCart(); + $this->miniShoppingCart->clickProceedToCheckoutButton(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ProceedToCheckoutStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ProceedToCheckoutStep.php index 1172529ea5e3d..5124d550c5d30 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ProceedToCheckoutStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/ProceedToCheckoutStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; + $this->customerAccountCreatePage = $customerAccountCreatePage; $this->customer = $customer; $this->logoutCustomerOnFrontend = $logoutCustomerOnFrontend; $this->clickProceedToCheckoutStep = $clickProceedToCheckoutStep; @@ -79,6 +90,17 @@ public function __construct( * @return void */ public function run() + { + $this->processLogin(); + $this->processRegister(); + } + + /** + * Process login action. + * + * @return void + */ + private function processLogin() { if ($this->checkoutMethod === 'login') { if ($this->checkoutOnepage->getAuthenticationPopupBlock()->isVisible()) { @@ -87,17 +109,37 @@ public function run() } else { $this->checkoutOnepage->getLoginBlock()->loginCustomer($this->customer); } + } elseif ($this->checkoutMethod === 'guest') { + $this->checkoutOnepage->getLoginBlock()->fillGuestFields($this->customer); + } elseif ($this->checkoutMethod === 'sign_in') { + $this->checkoutOnepage->getAuthenticationWrapperBlock()->signInLinkClick(); + $this->checkoutOnepage->getAuthenticationWrapperBlock()->loginCustomer($this->customer); + } + } + + /** + * Process customer register action. + * + * @return void + */ + private function processRegister() + { + if ($this->checkoutMethod === 'register_before_checkout') { + $this->checkoutOnepage->getAuthenticationPopupBlock()->createAccount(); + $this->customerAccountCreatePage->getRegisterForm()->registerCustomer($this->customer); } } /** - * Logout customer on fronted. + * Logout customer on frontend. * * @return void */ public function cleanup() { - if ($this->checkoutMethod === 'login') { + if ($this->checkoutMethod === 'login' || + $this->checkoutMethod === 'sign_in' || + $this->checkoutMethod === 'register_before_checkout') { $this->logoutCustomerOnFrontend->run(); } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php index 1f5d80bdbde49..40664160b6b08 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/SelectPaymentMethodStep.php @@ -1,74 +1,79 @@ checkoutOnepage = $checkoutOnepage; $this->payment = $payment; - if (isset($creditCard['dataset'])) { - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); - } + $this->creditCard = $creditCard; + $this->fillCreditCardOn3rdParty = $fillCreditCardOn3rdParty; } /** - * Run step that selecting payment method + * Run step that selecting payment method. * * @return void */ public function run() { if ($this->payment['method'] !== 'free') { - $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment, $this->creditCard); + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod( + $this->payment, + $this->creditCard, + $this->fillCreditCardOn3rdParty + ); } } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml index 6dc1b3b0c67ed..cf1bd9cdc0da0 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/di.xml @@ -1,14 +1,170 @@ - - - - middle - - + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S1 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S0 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S1 + + + + + S0 + + + + + S1 + + diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml index a26a2cead49b0..6c795fc020f47 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/testcase.xml @@ -1,7 +1,7 @@ @@ -22,4 +22,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Adminhtml/AgreementGrid.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Adminhtml/AgreementGrid.php index b78007e4fe262..f26c3d0a0bbc9 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Adminhtml/AgreementGrid.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Adminhtml/AgreementGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Multishipping/MultishippingAgreementReview.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Multishipping/MultishippingAgreementReview.php index d31953a57eb2e..f5f4229c8afc1 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Multishipping/MultishippingAgreementReview.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Block/Multishipping/MultishippingAgreementReview.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Fixture/CheckoutAgreement/Stores.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Fixture/CheckoutAgreement/Stores.php index dbcc5c1fedaba..bb9b3212f618a 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Fixture/CheckoutAgreement/Stores.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Fixture/CheckoutAgreement/Stores.php @@ -1,6 +1,6 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/Adminhtml/CheckoutAgreementNew.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/Adminhtml/CheckoutAgreementNew.xml index 92f2fbcea5c39..d1e9f7029dd34 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/Adminhtml/CheckoutAgreementNew.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/Adminhtml/CheckoutAgreementNew.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/CheckoutOnepage.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/CheckoutOnepage.xml index d50bbf09a8d9d..32b08a9ae8af9 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/CheckoutOnepage.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/CheckoutOnepage.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/MultishippingCheckoutOverview.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/MultishippingCheckoutOverview.xml index d6b9153414246..b31297f22ffe8 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/MultishippingCheckoutOverview.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Page/MultishippingCheckoutOverview.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/CheckoutAgreement.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/CheckoutAgreement.xml index 78b84bda18e0d..291f93aec3be7 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/CheckoutAgreement.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/CheckoutAgreement.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/ConfigData.xml index db3c99cdcff02..4321a26322f85 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/CreateTermEntityTest.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/CreateTermEntityTest.php index 21f48abef963d..14b21b39a42b1 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/CreateTermEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/CreateTermEntityTest.php @@ -1,6 +1,6 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, severity:S3 checkout_term_condition catalogProductSimple::default name%isolation% @@ -26,6 +26,7 @@ + severity:S3 checkout_term_condition catalogProductSimple::default name%isolation% @@ -43,6 +44,7 @@ + severity:S3 checkout_term_condition catalogProductSimple::default name%isolation% @@ -60,7 +62,7 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, severity:S3 checkout_term_condition catalogProductSimple::default catalogProductSimple::default diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/DeleteTermEntityTest.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/DeleteTermEntityTest.php index 2c65150aa6973..4f76fa784a0a9 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/DeleteTermEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/DeleteTermEntityTest.php @@ -1,6 +1,6 @@ + severity:S3 checkout_term_condition catalogProductSimple::default term_enabled_text diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml index 1387c7e1e1268..f18bc8059d854 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml @@ -1,13 +1,14 @@ + severity:S2 Stores > Terms and Conditions Terms and Conditions diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/UpdateTermEntityTest.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/UpdateTermEntityTest.php index 277f38e0c7e1f..22ce301ebfbf6 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/UpdateTermEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/UpdateTermEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 checkout_term_condition catalogProductSimple::default term_disabled_text @@ -26,6 +27,7 @@ + severity:S3 checkout_term_condition catalogProductSimple::default term_disabled_html @@ -44,6 +46,7 @@ + severity:S3 checkout_term_condition catalogProductSimple::default term_enabled_text diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestStep/CheckTermOnMultishippingStep.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestStep/CheckTermOnMultishippingStep.php index 995091d402d3c..1f3ee113b017d 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestStep/CheckTermOnMultishippingStep.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestStep/CheckTermOnMultishippingStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/di.xml index 7dc8356351f2f..10d53905ce2f2 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/di.xml @@ -1,14 +1,44 @@ - - - high - - + + + S3 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S3 + + diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/testcase.xml index e5c680a6de748..094f3b7b9a36c 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/etc/testcase.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/CmsGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/CmsGrid.php index b410888898d40..b5f209da7f5c9 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/CmsGrid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Block/CmsGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.php index 9d7386380a090..8d031c37c4133 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.php @@ -1,6 +1,6 @@ openTab('content'); + /** @var \Magento\Cms\Test\Block\Adminhtml\Page\Edit\Tab\Content $contentTab */ + $contentTab = $this->getTab('content'); + $contentTab->clickInsertVariable(); + $this->waitForElementNotVisible($this->loader); + return $contentTab->isVariablesBlockVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml index 0d19cfd80f3df..58533aa8680dd 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php index a4f1bd4d1f85e..ea141f20b0634 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/Tab/Content.php @@ -1,6 +1,6 @@ '' ]; } + + /** + * Check if system variables block is visible. + * + * @return bool + */ + public function isVariablesBlockVisible() + { + return $this->_rootElement->find($this->systemVariableBlock, Locator::SELECTOR_XPATH)->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Grid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Grid.php index cc89afe1e6134..954739fbbcc73 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Grid.php @@ -1,6 +1,6 @@ open(); + $filter = ['title' => $cms->getTitle()]; + $cmsIndex->getCmsPageGridBlock()->searchAndOpen($filter); + + $cmsFormData = $cmsPageNew->getPageForm()->getData($cms); + $cmsFixtureData = $cms->getData(); + $errors = $this->verifyData($cmsFixtureData, $cmsFormData); + \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php index b998ff2f4f4a8..02d6433cec7a8 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php @@ -1,6 +1,6 @@ $cms->getTitle(), + 'is_active' => $expectedStatus ]; $cmsIndex->open(); \PHPUnit_Framework_Assert::assertTrue( diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php index c6f80c5dc8960..3d537d5744382 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php @@ -1,6 +1,6 @@ open($_ENV['app_frontend_url'] . $cms->getIdentifier()); + $fixtureContent = $cms->getContent(); + \PHPUnit_Framework_Assert::assertContains( + $displayContent != null ? $displayContent : $fixtureContent['content'], + $frontCmsPage->getCmsPageBlock()->getPageContent(), + 'Wrong content is displayed.' + ); + } + + /** + * CMS Page content equals to data from fixture. + * + * @return string + */ + public function toString() + { + return 'CMS Page content equals to data from fixture.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php index 51e9b428892cc..525e08d37cb2a 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php @@ -1,6 +1,6 @@ open(); $filter = ['title' => $cms->getTitle()]; @@ -46,7 +48,7 @@ public function processAssert( $fixtureContent = $cms->getContent(); \PHPUnit_Framework_Assert::assertContains( - $fixtureContent['content'], + $displayContent != null ? $displayContent : $fixtureContent['content'], $frontCmsPage->getCmsPageBlock()->getPageContent(), 'Wrong content is displayed.' ); diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php index a22871aaf467e..b90201e53b14b 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php @@ -1,6 +1,6 @@ processAssert($cmsPage, $frontCmsIndex, $cmsIndex, $browser); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Pages with message "404 Not Found" are displayed.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesInGrid.php new file mode 100644 index 0000000000000..7058586437008 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesInGrid.php @@ -0,0 +1,46 @@ +processAssert($cmsIndex, $cmsPage, $expectedStatus); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Cms pages are present in pages grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesOnFrontendMultipleStoreViews.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesOnFrontendMultipleStoreViews.php new file mode 100644 index 0000000000000..660aa0be076a1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesOnFrontendMultipleStoreViews.php @@ -0,0 +1,57 @@ +open($_ENV['app_frontend_url'] . $cmsPage->getIdentifier()); + $storeName = $cmsPage->getDataFieldConfig('store_id')['source']->getStore()->getData()['name']; + $cmsIndex->getStoreSwitcherBlock()->selectStoreView($storeName); + \PHPUnit_Framework_Assert::assertContains( + $displayContent != null ? $displayContent : $cmsPage->getContent()['content'], + $frontCmsPage->getCmsPageBlock()->getPageContent(), + 'Wrong content page ' . $cmsPage->getTitle() . ' is displayed on store ' . $storeName . '.' + ); + } + } + + /** + * CMS Page content equals to data from fixture. + * + * @return string + */ + public function toString() + { + return 'Created CMS Page displayed on store view with expected content.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php index f9b19ee43f0b7..6b6fbf35e45c1 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsBlock/Stores.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsBlock/Stores.php index 72cfa2767dc85..a839f38374f35 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsBlock/Stores.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsBlock/Stores.php @@ -1,6 +1,6 @@ @@ -34,6 +34,6 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsPage/Content.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsPage/Content.php index c6d1e0a3a412f..2ea2cfd5823f0 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsPage/Content.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Fixture/CmsPage/Content.php @@ -1,6 +1,6 @@ params = $params; + $this->fixtureFactory = $fixtureFactory; + $this->variationData = $data; + } + + /** + * Return prepared data set. + * + * @param string $key [optional] + * @return mixed + */ + public function getData($key = null) + { + if (null === $this->data) { + $this->processData(); + } + return parent::getData($key); + } + + /** + * Return Store fixture. + * + * @return Store + */ + public function getStore() + { + return $this->store; + } + + /** + * Process input data. + * + * @return void + */ + private function processData() + { + if (is_array($this->variationData) && isset($this->variationData['dataset'])) { + $store = $this->fixtureFactory->createByCode('store', $this->variationData); + /** @var Store $store */ + if (!$store->getStoreId()) { + $store->persist(); + } + $this->store = $store; + $this->data = $store->getGroupId() . '/' . $store->getName(); + } else { + $this->data = $this->variationData; + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsBlock/CmsBlockInterface.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsBlock/CmsBlockInterface.php index e3c3d937a8110..d2d5d58af445c 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsBlock/CmsBlockInterface.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsBlock/CmsBlockInterface.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockIndex.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockIndex.xml index e23472508e83a..9822049563fc3 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockIndex.xml @@ -1,7 +1,7 @@ @@ -9,6 +9,6 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml index 7b8249fc0aa5b..add41532f39ad 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsBlockNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageIndex.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageIndex.xml index ed2037cf893a3..b5c1083e6baeb 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageIndex.xml @@ -1,14 +1,14 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml index 3cfbe49edf746..f976c5682f05b 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/Adminhtml/CmsPageNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml index c4a98c9ba3223..e12e246f2d1ce 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml @@ -1,7 +1,7 @@ @@ -11,11 +11,12 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml index 45cd2cf42edfe..8bb4e4d80ade0 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsPage.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsBlock.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsBlock.xml index a7f302da5a6bf..ee7efb4171bd9 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsBlock.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsBlock.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage.xml index 7795bb150e326..a52f74ad39a9f 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage/Content.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage/Content.xml index 22290d358cab9..3b23533a69a4b 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage/Content.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/CmsPage/Content.xml @@ -1,7 +1,7 @@ @@ -19,6 +19,24 @@ + + + Recently Compared Products + 10 + Compared Products Grid Template + + + + + + Catalog New Products List + All products + Yes + 10 + New Products Grid Template + + + CMS Page Link diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/ConfigData.xml index df22136e0a8c2..18780efe0525a 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/UrlRewrite.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/UrlRewrite.xml index 9dfe010246a6b..34f265c719356 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/UrlRewrite.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Repository/UrlRewrite.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/AbstractCmsBlockEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/AbstractCmsBlockEntityTest.php index 5d3739c8a098b..112e8671e8118 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/AbstractCmsBlockEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/AbstractCmsBlockEntityTest.php @@ -1,6 +1,6 @@ Elements > Pages. + * 3. Perform mass action on the newly created pages. + * 4. Perform assertions. + * + * @group CMS_Content + * @ZephyrId MAGETWO-35581 + */ +class CmsPageMassActionTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + /* end tags */ + + /** + * CmsIndex page. + * + * @var CmsPageIndex + */ + protected $cmsIndex; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Inject pages. + * + * @param CmsPageIndex $cmsIndex + * @param FixtureFactory $fixtureFactory + * @return void + */ + public function __inject(CmsPageIndex $cmsIndex, FixtureFactory $fixtureFactory) + { + $this->cmsIndex = $cmsIndex; + $this->fixtureFactory = $fixtureFactory; + } + + /** + * Creating Cms page. + * + * @param array $cmsPages + * @param string $action + * @return array + */ + public function test(array $cmsPages, $action) + { + // Preconditions + $pages = []; + $pagesForMassAction = []; + foreach ($cmsPages as $key => $dataset) { + $pages[$key] = $this->fixtureFactory->createByCode('cmsPage', ['dataset' => $dataset]); + $pages[$key]->persist(); + $pagesForMassAction[$key] = ['id' => $pages[$key]->getPageId()]; + } + + // Test steps + $this->cmsIndex->open(); + $this->cmsIndex->getCmsPageGridBlock()->massaction($pagesForMassAction, $action); + + return [ + 'cmsPages' => $pages + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CmsPageMassActionTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CmsPageMassActionTest.xml new file mode 100644 index 0000000000000..982111191549c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CmsPageMassActionTest.xml @@ -0,0 +1,19 @@ + + + + + + default + 3_column_template + Disable + Disabled + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsBlockEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsBlockEntityTest.php index 7e3c3f0ebb3c9..eac94517dbdd0 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsBlockEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsBlockEntityTest.php @@ -1,6 +1,6 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, severity:S1 block_%isolation% identifier_%isolation% All Store Views @@ -19,13 +19,13 @@ + severity:S2 block_%isolation% identifier_%isolation% default No description_%isolation% - diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityMultipleStoreViewsTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityMultipleStoreViewsTest.php new file mode 100644 index 0000000000000..af4ee7d0cbd39 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityMultipleStoreViewsTest.php @@ -0,0 +1,87 @@ + Elements > Pages. + * 3. Click "Add New Page", add page contents according to Test Data(Default Store View) and save. + * 4. Click "Add New Page", add page contents according to Test Data(Custom Store View 1) and save. + * 5. Click "Add New Page", add page contents according to Test Data(Custom Store View 2) and save. + * 6. Save CMS Page. + * 7. Verify created CMS Page. + * + * @group CMS_Content + * @ZephyrId MAGETWO-52467 + */ +class CreateCmsPageEntityMultipleStoreViewsTest extends Injectable +{ + /** + * CmsIndex page. + * + * @var CmsPageIndex + */ + protected $cmsIndex; + + /** + * CmsPageNew page. + * + * @var CmsPageNew + */ + protected $cmsPageNew; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Inject pages. + * + * @param CmsPageIndex $cmsIndex + * @param CmsPageNew $cmsPageNew + * @param FixtureFactory $fixtureFactory + * @return void + */ + public function __inject(CmsPageIndex $cmsIndex, CmsPageNew $cmsPageNew, FixtureFactory $fixtureFactory) + { + $this->cmsIndex = $cmsIndex; + $this->cmsPageNew = $cmsPageNew; + $this->fixtureFactory = $fixtureFactory; + } + + /** + * Page cache for different CMS pages on multiple store views. + * + * @param array $cmsPages + * @return array + */ + public function test(array $cmsPages) + { + // Steps + $cmsPageFixtures = []; + foreach ($cmsPages as $cmsPage) { + $cmsPageFixture = $this->fixtureFactory->createByCode('cmsPage', ['data' => $cmsPage]); + $cmsPageFixtures[] = $cmsPageFixture; + + $this->cmsIndex->open(); + $this->cmsIndex->getPageActionsBlock()->addNew(); + $this->cmsPageNew->getPageForm()->fill($cmsPageFixture); + $this->cmsPageNew->getPageMainActions()->save(); + } + + return ['cmsPages' => $cmsPageFixtures]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityMultipleStoreViewsTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityMultipleStoreViewsTest.xml new file mode 100644 index 0000000000000..dd1c5cccea3ea --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityMultipleStoreViewsTest.xml @@ -0,0 +1,36 @@ + + + + + + Yes + NewCmsPage + default + cms_page_text_content%isolation% + default + 1 column + identifier_%isolation% + Yes + NewCmsPage + custom + cms_page_text_content%isolation% + compared_products_grid + 1 column + identifier_%isolation% + Yes + NewCmsPage + custom + cms_page_text_content%isolation% + new_products_grid + 1 column + identifier_%isolation% + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php index f5035a2eaf76d..0219a19c0be0f 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.php @@ -1,11 +1,12 @@ configData = $configData; + + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); // Steps $cms = $this->fixtureFactory->createByCode($fixtureType, ['data' => $data]); $this->cmsIndex->open(); @@ -85,4 +102,19 @@ public function test(array $data, $fixtureType) return ['cms' => $cms]; } + + /** + * Disable single store mode on config level. + * + * @return void + */ + public function tearDown() + { + if ($this->configData) { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => 'enable_single_store_mode', 'rollback' => true] + )->run(); + } + } } diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml index 60b440fc0868b..94dcd86bf71ce 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageEntityTest.xml @@ -1,25 +1,26 @@ + test_type:acceptance_test, test_type:extended_acceptance_test, severity:S1 cmsPage Yes NewCmsPage%isolation% identifier-%isolation% All Store Views cms_page_text_content%isolation% - test_type:acceptance_test, test_type:extended_acceptance_test + severity:S1 cmsPage Yes NewCmsPage%isolation% @@ -30,6 +31,7 @@ + severity:S1 cmsPage Yes NewCmsPage%isolation% @@ -39,11 +41,10 @@ default General Contact Name - - + severity:S3 cmsPage NewCmsPage%isolation% identifier-%isolation% @@ -51,9 +52,32 @@ No cms_page_text_content%isolation% - - + + severity:S2 + cmsPage + NewCmsPage%isolation% + identifier-%isolation% + Main Website/Main Website Store/Default Store View + Yes + \\{{block class='Magento\Framework\View\Element\Text' text='bla bla bla' cache_key='BACKEND_ACL_RESOURCES' cache_lifetime=999\}} + bla bla bla + + + + + + test_type:acceptance_test, test_type:extended_acceptance_test + enable_single_store_mode + cmsPage + Yes + NewCmsPage%isolation% + identifier-%isolation% + cms_page_text_content%isolation% + + + + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageRewriteEntityTest.php index 296525540073f..d7e27184ddcf7 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCmsPageRewriteEntityTest.php @@ -1,6 +1,6 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, severity:S1 For CMS page cms/page/view/page_id/%cmsPage::default% request_path%isolation% @@ -19,6 +19,7 @@ + severity:S1 For CMS page cms/page/view/page_id/%cmsPage::default% request_path%isolation%.html @@ -29,6 +30,7 @@ + severity:S1 For CMS page cms/page/view/page_id/%cmsPage::default% request_path%isolation%.htm @@ -39,6 +41,7 @@ + severity:S1 For CMS page cms/page/view/page_id/%cmsPage::default% request_path%isolation%.aspx diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCustomUrlRewriteEntityTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCustomUrlRewriteEntityTest.xml index 9f14cefa8147d..9f73c17b5f5ff 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCustomUrlRewriteEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/CreateCustomUrlRewriteEntityTest.xml @@ -1,13 +1,14 @@ + severity:S1 Custom Main Website/Main Website Store/Default Store View cms/page/view/page_id/%cmsPage::default% @@ -15,10 +16,10 @@ No test description_full path - + severity:S1 Custom Main Website/Main Website Store/Default Store View cms/page/view/page_id/%cmsPage::default% @@ -26,7 +27,6 @@ Temporary (302) test description_full path - diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php index ad2ae5689c985..c1118dc977f15 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsBlockEntityTest.php @@ -1,6 +1,6 @@ + severity:S1, stable:no diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageEntityTest.php index 25225917014fc..a1ad967790415 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageEntityTest.php @@ -1,6 +1,6 @@ + severity:S1, stable:no default diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageUrlRewriteEntityTest.php index 68d0ae541253d..304dddf3805f2 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/DeleteCmsPageUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 cms_default_no_redirect + severity:S2 cms_default_permanent_redirect - + severity:S2 cms_default_temporary_redirect - diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFilteringTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFilteringTest.xml index af26b1f11f177..882b3a0ebdbb6 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFilteringTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFilteringTest.xml @@ -1,13 +1,14 @@ + severity:S3 Verify cms page grid filtering 2 cmsPage @@ -28,6 +29,7 @@ + severity:S3 Verify cms block grid filtering 2 cmsBlock diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFullTextSearchTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFullTextSearchTest.xml index 21a0dd32a56b2..be0327d8bcad7 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFullTextSearchTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridFullTextSearchTest.xml @@ -1,13 +1,14 @@ + severity:S3, stable:no Verify cms page grid full text search 2 cmsPage @@ -19,6 +20,7 @@ + severity:S3 Verify cms blocks grid full text search 2 cmsBlock diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml index 595277423b39c..50db5a9ffa3d6 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/GridSortingTest.xml @@ -1,13 +1,14 @@ + severity:S3, stable:no Verify cms page grid sorting ID @@ -18,6 +19,7 @@ + severity:S3, stable:no Verify cms blocks grid sorting - diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml index 38c9e8cf8f21d..ceed8a66f64eb 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml @@ -1,18 +1,20 @@ + severity:S2 Content > Pages Pages + severity:S2 Content > Blocks Blocks diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsBlockEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsBlockEntityTest.php index 8fa92fba59f8e..b960d07c0c527 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsBlockEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsBlockEntityTest.php @@ -1,6 +1,6 @@ + severity:S1 block_updated_%isolation% identifier_updated_%isolation% all_store_views @@ -18,13 +19,13 @@ + severity:S3 block_updated_%isolation% identifier_updated_%isolation% default No description_updated_%isolation% - diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageEntityTest.php index b16f4384f27d5..954d93d79dd86 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageEntityTest.php @@ -1,6 +1,6 @@ + severity:S3, to_maintain:yes CmsPageEdited%isolation% No cms_page_text_content_after_edit - + severity:S1, to_maintain:yes CmsPageEdited%isolation% cms_page_url_edited_%isolation% Content Heading TextEdited cms_page_text_content_after_edit + diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageRewriteEntityTest.php index 43fd7e69ac359..070d9b3fadf39 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/UpdateCmsPageRewriteEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 cms_default_no_redirect Main Website/Main Website Store/%default% request_path%isolation% @@ -17,6 +18,7 @@ + severity:S2 cms_default_temporary_redirect Main Website/Main Website Store/Default Store View request_path%isolation%.html @@ -26,6 +28,7 @@ + severity:S2 cms_default_permanent_redirect Main Website/Main Website Store/Default Store View request_path%isolation%.htm diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/etc/curl/di.xml index b6d3e8a1aaf0e..aaad503c15e35 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/etc/di.xml index f4b96844b2738..6da870c5931d7 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/etc/di.xml @@ -1,29 +1,89 @@ - + - high + S1 - + + + S2 + + + - high + S3 - high + S3 - + + + S1 + + + + + S1 + + + + + S1 + + + + + S2 + + + + + S1 + + + + + S2 + + + + + S2 + + + + + S3 + + + + + S1 + + + + + S1 + + + + + S1 + + + - high + S1 diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Block/System/Config/AdminForm.php b/dev/tests/functional/tests/app/Magento/Config/Test/Block/System/Config/AdminForm.php index 38bb261cb790e..8fe15ebcb22ad 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/Block/System/Config/AdminForm.php +++ b/dev/tests/functional/tests/app/Magento/Config/Test/Block/System/Config/AdminForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php index 60d43e1da95f7..d8be9fe5baf0b 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php +++ b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php @@ -1,6 +1,6 @@ prepareScopeData(); unset($this->fixtureData['scope']); } - $this->data = $this->fixtureData; + $this->data = $this->replacePlaceholders($this->fixtureData); } return parent::getData($key); } + /** + * Replace placeholders in parameters array. + * + * @param array $data + * @return array + */ + private function replacePlaceholders(array $data) + { + foreach ($data as &$params) { + $params = array_map(function ($value) { + if (is_string($value)) { + $value = str_replace( + '{{basic_url_to_secure}}', + preg_replace('/(http[s]?)/', 'https', $_ENV['app_frontend_url']), + $value + ); + $value = str_replace( + '{{basic_url_to_unsecure}}', + preg_replace('/(http[s]?)/', 'http', $_ENV['app_frontend_url']), + $value + ); + } + return $value; + }, $params); + } + return $data; + } + /** * Prepare scope data. * diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/ConfigDataInterface.php b/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/ConfigDataInterface.php index 6820f08b93fa7..22d93268df68a 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/ConfigDataInterface.php +++ b/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/ConfigDataInterface.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php b/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php index a691176094509..b72ee84a3a406 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php +++ b/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php @@ -1,6 +1,6 @@ fixtureFactory = $fixtureFactory; - $this->adminCache = $adminCache; $this->configData = $configData; $this->rollback = $rollback; $this->flushCache = $flushCache; + $this->cache = $cache; } /** @@ -95,12 +94,9 @@ public function run() $config->persist(); $result[] = $config; } - } - - if ($this->flushCache) { - $this->adminCache->open(); - $this->adminCache->getActionsBlock()->flushMagentoCache(); - $this->adminCache->getMessagesBlock()->waitSuccessMessage(); + if ($this->flushCache) { + $this->cache->flush(); + } } return ['config' => $result]; diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Config/Test/etc/curl/di.xml index 48f993fe6cce9..7ac2eb9207104 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Config/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php index d7fcc85e65f7f..01d9a0be5cc9a 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AffectedAttributeSet.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AssociatedProductGrid.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AssociatedProductGrid.php index 374e7503f2357..e6d9d3f235982 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AssociatedProductGrid.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/AssociatedProductGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.php index a09c9b4dd6e00..94da9ee15eaf4 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/NewConfigurableAttributeForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config.php index c26421c5a65d0..bc2d40a0695dd 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config.php @@ -1,6 +1,6 @@ getAttributesGrid()->resetFilter(); + $this->getTemplateBlock()->waitLoader(); $attributesList = $this->browser->find($this->selectedAttributes)->getText(); if ($attributesList != '--') { $this->getAttributesGrid()->deselectAttributes(); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.xml index 61b88a1648ff3..3aba320e91f3f 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/AttributeSelector.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/AttributeSelector.php index 5a6ebf949ec08..08efb92344073 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/AttributeSelector.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/Edit/Section/Variations/Config/Attribute/AttributeSelector.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php index 9484e7439c057..4cfe07d1f836f 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/FormPageActions.php @@ -1,6 +1,6 @@ getConfigurableAttributesData(); + $productItems[] = ['sku' => $product->getSku()]; + foreach ($configurableAttributesData['matrix'] as $variation) { + $productItems[] = ['sku' => $variation['sku']]; + } + + return $productItems; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php index 80ea10808de0a..53dc260f0c6ec 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Adminhtml/Product/ProductForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View.php index 69c22b37edc0a..63df6ef37c909 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Block/Product/View.php @@ -1,6 +1,6 @@ getOptionPrice($variationOptions, $attributesData); + //Select all options specified in variation + $this->chooseOptions($variationOptions, $attributesData); + $result[$variation]['price'] = $this->getOptionPrice(); + $tierPrices = $this->getOptionTierPrices(); + if (count($tierPrices) > 0) { + $result[$variation]['tierPrices'] = $tierPrices; + } } return $result; @@ -106,25 +118,34 @@ public function getOptionsPrices(FixtureInterface $product) /** * Get option price * - * @param array $variationOptions - * @param array $attributesData * @return null|string */ - protected function getOptionPrice($variationOptions, $attributesData) + protected function getOptionPrice() { - //Select all options specified in variation - foreach ($variationOptions as $variationSelection) { - list ($attribute, $option) = explode(':', $variationSelection); - $attributeTitle = $attributesData[$attribute]['label']; - $optionTitle = $attributesData[$attribute]['options'][$option]['label']; - $this->selectOption($attributeTitle, $optionTitle); - } - $priceBlock = $this->getPriceBlock(); $price = ($priceBlock->isOldPriceVisible()) ? $priceBlock->getOldPrice() : $priceBlock->getPrice(); return $price; } + /** + * Get tier prices of all variations + * + * @return array + */ + private function getOptionTierPrices() + { + $prices = []; + $tierPricesNodes = $this->_rootElement->getElements($this->tierPricesSelector); + foreach ($tierPricesNodes as $node) { + preg_match('#^[^\d]+(\d+)[^\d]+(\d+(?:(?:,\d+)*)+(?:.\d+)*).*#i', $node->getText(), $matches); + $prices[] = [ + 'qty' => isset($matches[1]) ? $matches[1] : null, + 'price_qty' => isset($matches[2]) ? $matches[2] : null, + ]; + } + return $prices; + } + /** * Get block price. * @@ -139,6 +160,8 @@ protected function getPriceBlock() } /** + * Select option from the select element. + * * @param string $attributeTitle * @param string $optionTitle */ @@ -147,4 +170,22 @@ protected function selectOption($attributeTitle, $optionTitle) $this->_rootElement->find(sprintf($this->optionSelector, $attributeTitle), Locator::SELECTOR_XPATH, 'select') ->setValue($optionTitle); } + + /** + * Choose options of the configurable product + * + * @param $variationOptions + * @param $attributesData + * @return void + */ + protected function chooseOptions($variationOptions, $attributesData) + { + //Select all options specified in variation + foreach ($variationOptions as $variationSelection) { + list ($attribute, $option) = explode(':', $variationSelection); + $attributeTitle = $attributesData[$attribute]['label']; + $optionTitle = $attributesData[$attribute]['options'][$option]['label']; + $this->selectOption($attributeTitle, $optionTitle); + } + } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php index 9af9a9d604ded..58068dd9c024b 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php @@ -1,6 +1,6 @@ product->getConfigurableAttributesData(); - - foreach ($configurableOptions['matrix'] as $option) { - $price = $price === null ? $option['price'] : $price; - if ($price > $option['price']) { - $price = $option['price']; + $priceDataConfig = $this->product->getDataFieldConfig('price'); + if (isset($priceDataConfig['source'])) { + $priceData = $priceDataConfig['source']->getPriceData(); + if (isset($priceData['price_from'])) { + $price = $priceData['price_from']; } } + if (null === $price) { + $configurableOptions = $this->product->getConfigurableAttributesData(); + foreach ($configurableOptions['matrix'] as $option) { + $price = $price === null ? $option['price'] : $price; + if ($price > $option['price']) { + $price = $option['price']; + } + } + } return $price; } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductsQtyAfterReorder.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductsQtyAfterReorder.php new file mode 100644 index 0000000000000..4b342e69191e5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductsQtyAfterReorder.php @@ -0,0 +1,70 @@ +createByCode('orderInjectable', [ + 'dataset' => 'default', + 'data' => [ + 'entity_id' => [ + 'products' => $order->getEntityId()['products'], + ] + ] + ]); + $newOrder->persist(); + $assertProductsQty->processAssert( + $newOrder, + $productGrid, + $productPage, + $fixtureFactory, + $assertProductForm, + $assertConfigurableProductForm + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Products quantity is correct after reorder.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php new file mode 100644 index 0000000000000..9553f8af75ead --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php @@ -0,0 +1,77 @@ +open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $this->assertPrice($view, $basePrice); + + $view->getViewBlock()->configure($product); + $this->assertPrice($view, $configuredPrices['custom_currency']); + + $cmsIndex->getCurrencyBlock()->switchCurrency($baseCurrency); + $view->getViewBlock()->configure($product); + $this->assertPrice($view, $configuredPrices['base_currency']); + } + + /** + * Assert price. + * + * @param CatalogProductView $view + * @param string $price + * @param string $currency [optional] + */ + public function assertPrice(CatalogProductView $view, $price, $currency = '') + { + \PHPUnit_Framework_Assert::assertEquals( + $price, + $view->getViewBlock()->getPriceBlock()->getPrice($currency), + 'Wrong price is displayed on Product page.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Currency rate has been applied correctly on Configurable Product page."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php index 2763563c86df5..4c915adc7119e 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php @@ -1,6 +1,6 @@ fixtureFactory = $fixtureFactory; + parent::__construct($objectManager, $eventManager); + } + + /** + * Assert form data equals fixture data + * + * @param OrderInjectable $order + * @param array $data + * @param CatalogProductIndex $productGrid + * @param CatalogProductEdit $productPage + * @return void + */ + public function processAssert( + OrderInjectable $order, + array $data, + CatalogProductIndex $productGrid, + CatalogProductEdit $productPage + ) { + $product = $this->getProduct($order, $data); + $this->objectManager->get(\Magento\Catalog\Test\Constraint\AssertProductForm::class)->processAssert( + $product, + $productGrid, + $productPage + ); + } + + /** + * Get product's fixture. + * + * @param OrderInjectable $order + * @param array $data + * @param int $index [optional] + * @return FixtureInterface + */ + protected function getProduct(OrderInjectable $order, array $data, $index = 0) + { + if (!isset($data['items_data'][$index]['back_to_stock']) + || $data['items_data'][$index]['back_to_stock'] != 'Yes' + ) { + return $order->getEntityId()['products'][$index]; + } + $product = $order->getEntityId()['products'][$index]; + $productData = $product->getData(); + $checkoutDataQty = $productData['checkout_data']['qty']; + + $productKey = ''; + foreach ($productData['checkout_data']['options']['configurable_options'] as $option) { + $productKey .= ' ' . $option['title'] . ':' . $option['value']; + } + $productKey = trim($productKey); + $optionProduct = $productData['configurable_attributes_data']['matrix'][$productKey]; + $optionProduct['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']); + $productData = $optionProduct; + + $productData = array_diff_key($productData, array_flip($this->skipFields)); + + return $this->fixtureFactory->create(get_class($product), ['data' => $productData]); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product qty was decreased after creditmemo creation.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductTierPriceOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductTierPriceOnProductPage.php new file mode 100644 index 0000000000000..deddbf378f544 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductTierPriceOnProductPage.php @@ -0,0 +1,47 @@ +pageView->getConfigurableAttributesBlock(); + $formTierPrices = $optionsBlock->getOptionsPrices($this->product); + $products = ($this->product->getDataFieldConfig('configurable_attributes_data')['source'])->getProducts(); + foreach ($products as $key => $product) { + $configuredTierPrice = []; + $actualTierPrices = isset($formTierPrices[$key]['tierPrices']) ? $formTierPrices[$key]['tierPrices'] : []; + $tierPrices = $product->getTierPrice() ?: []; + foreach ($tierPrices as $tierPrice) { + $configuredTierPrice[] = [ + 'qty' => $tierPrice['price_qty'], + 'price_qty' => $tierPrice['price'], + ]; + } + + if ($configuredTierPrice != $actualTierPrices) { + $errors[] = sprintf('Tier prices for variation %s doesn\'t equals to configured.', $key); + } + } + + return $errors; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php index d2a999627cb95..905a382f01897 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/Cart/Item.php @@ -1,14 +1,11 @@ getCheckoutData(); + parent::getData($key); + $productData = $this->product->getData(); + $checkoutData = $this->product->getCheckoutData(); $cartItem = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; - $attributesData = $product->getConfigurableAttributesData()['attributes_data']; + $attributesData = $this->product->getConfigurableAttributesData()['attributes_data']; $checkoutConfigurableOptions = isset($checkoutData['options']['configurable_options']) ? $checkoutData['options']['configurable_options'] : []; + $attributeKey = []; foreach ($checkoutConfigurableOptions as $key => $checkoutConfigurableOption) { $attribute = $checkoutConfigurableOption['title']; $option = $checkoutConfigurableOption['value']; - + $attributeKey[] = "$attribute:$option"; $checkoutConfigurableOptions[$key] = [ 'title' => isset($attributesData[$attribute]['label']) ? $attributesData[$attribute]['label'] @@ -48,10 +47,19 @@ public function __construct(FixtureInterface $product) : $option, ]; } + $attributeKey = implode(' ', $attributeKey); + if (isset($productData['configurable_attributes_data']['matrix'][$attributeKey])) { + $cartItem['sku'] = $productData['configurable_attributes_data']['matrix'][$attributeKey]['sku']; + } else { + $cartItem['sku'] = $productData['sku']; + } + $cartItem['name'] = $productData['name']; $cartItem['options'] = isset($cartItem['options']) ? $cartItem['options'] + $checkoutConfigurableOptions : $checkoutConfigurableOptions; $this->data = $cartItem; + + return $this->data; } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml index dde6d465f6ee5..5964b0a66a976 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct/ConfigurableAttributesData.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct/ConfigurableAttributesData.php index 65f80eb714463..c9fe060645914 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct/ConfigurableAttributesData.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Fixture/ConfigurableProduct/ConfigurableAttributesData.php @@ -1,6 +1,6 @@ attributes as $attributeKey => $attribute) { $attributeData = $attribute->getData(); $options = []; - foreach ($attributeData['options'] as $key => $option) { $options['option_key_' . $key] = $option; } @@ -277,10 +276,12 @@ protected function prepareVariationsMatrix(array $data) $variationsMatrix = $this->addVariationMatrix($variationsMatrix, $attribute, $attributeKey); } - foreach ($data['matrix'] as $key => $value) { - if (isset($value['sku']) && $value['sku'] === '') { - unset($variationsMatrix[$key]['sku']); - unset($data['matrix'][$key]['sku']); + if (isset($data['matrix'])) { + foreach ($data['matrix'] as $key => $value) { + if (isset($value['sku']) && $value['sku'] === '') { + unset($variationsMatrix[$key]['sku']); + unset($data['matrix'][$key]['sku']); + } } } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/ConfigurableProductInterface.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/ConfigurableProductInterface.php index 9ffe38e9475bf..00383b62e33c1 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/ConfigurableProductInterface.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/ConfigurableProductInterface.php @@ -1,6 +1,6 @@ fields['product']['website_ids'])) { + foreach ($this->fixture->getDataFieldConfig('website_ids')['source']->getWebsites() as $key => $website) { + $this->fields['product']['website_ids'][$key] = $website->getWebsiteId(); + } + } else { + $website = \Magento\Mtf\ObjectManagerFactory::getObjectManager() + ->create(\Magento\Store\Test\Fixture\Website::class, ['dataset' => 'default']); + $this->fields['product']['website_ids'][] = $website->getWebsiteId(); + } + } + /** * Preparation of attribute set data. * @@ -154,7 +172,7 @@ protected function prepareConfigurableMatrix(FixtureInterface $product) $keyIds[] = $attribute['options'][$optionKey]['id']; $configurableAttribute[] = sprintf( '"%s":"%s"', - $attribute['attribute_code'], + isset($attribute['attribute_code']) ? $attribute['attribute_code'] : $attribute['frontend_label'], $attribute['options'][$optionKey]['id'] ); } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Webapi.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Webapi.php index fffbe9b89c850..3e64bf216c1aa 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Webapi.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Handler/ConfigurableProduct/Webapi.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CatalogProductNew.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CatalogProductNew.xml index 095f6d1e1dea2..36336e14a8f94 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CatalogProductNew.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CatalogProductNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CustomerIndexEdit.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CustomerIndexEdit.xml index 5e66d99d95e89..e70f76f6a44d7 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CustomerIndexEdit.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/CustomerIndexEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml index a67119cbf19aa..1c630c5ce674d 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Adminhtml/OrderCreateIndex.xml @@ -1,14 +1,14 @@ - - - - - + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml index c2c5d8428b480..71e9bf77e5d3d 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ @@ -10,6 +10,6 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml index 2a3703a106075..07d85bd5b3491 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml @@ -1,7 +1,7 @@ @@ -39,11 +39,76 @@ configurable_default + + default_subcategory + - + Test configurable product %isolation% sku_test_configurable_product_%isolation% + + 40 + price_40 + + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + two_options_with_assigned_product + + + Out of Stock + + + + default + + + + default + + + + + sku_test_configurable_product_%isolation% + sku_test_configurable_product_%isolation% + + price_40 + + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + default + + + In Stock + + + + default + + + + default + + + configurable_options_with_qty_1 + + + + + sku_test_configurable_product_%isolation% + sku_test_configurable_product_%isolation% price_40 @@ -272,6 +337,40 @@ + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + with_one_option_buy_all + + + In Stock + + + + default + + + + default + + + configurable_one_option + + + 40 + price_40 + + + Test configurable product %isolation% sku_test_configurable_product_%isolation% @@ -435,5 +534,365 @@ price_40 + + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + + 10 + + 10 + This item has weight + 5 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + two_options_with_assigned_product_special_price + + + In Stock + + + + default + + + + default + + + configurable_two_new_options_with_special_price + + + default_subcategory + + + + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + 49.99 + This item has weight + 5 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + two_options_with_assigned_product_special_price_2 + + + In Stock + + + + default + + + + default + + + two_fixed_radio_options + + + product_1_and_option_1 + + + default_subcategory + + + + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + 10 + This item has weight + 5 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + two_options_with_assigned_product_special_price_2 + + + In Stock + + + + default + + + + default + + + two_fixed_radio_options + + + product_1_and_option_2 + + + default_subcategory + + + + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + 10 + This item has weight + 5 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + two_options_with_assigned_product_special_price_2 + + + In Stock + + + + default + + + + default + + + two_fixed_radio_options + + + product_2_and_option_1 + + + default_subcategory + + + + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + 10 + This item has weight + 5 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + two_options_with_assigned_product_special_price_2 + + + In Stock + + + + default + + + + default + + + two_fixed_radio_options + + + product_2_and_option_2 + + + default_subcategory + + + + + Stellar Solar Jacket %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 5 + + 75 + price_75 + + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + three_options_with_sizes_S_M_L + + + custom_attribute_set_with_sizes + + + In Stock + + + + default + + + + configurable_the_first_option + + + default_subcategory + + + + + Stellar Solar Jacket %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 5 + + 75 + price_75 + + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + three_options_with_sizes_S_M_L + + + custom_attribute_set_with_sizes + + + In Stock + + + + default + + + + configurable_the_second_option + + + default_subcategory + + + + + Stellar Solar Jacket %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 5 + + 75 + price_75 + + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + three_options_with_sizes_S_M_L + + + custom_attribute_set_with_sizes + + + In Stock + + + + default + + + + configurable_the_third_option + + + default_subcategory + + + + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + + 40 + price_40 + + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + configurable_low_stock + + + In Stock + + + + default + + + + default + + + configurable_low_stock + + + + + Test configurable product %isolation% + sku_test_configurable_product_%isolation% + + 560 + + This item has weight + 2 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + one_option_with_simple_product + + + In Stock + + + + default + + + + default + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml index f075312343c21..135e5c1f705c1 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/CheckoutData.xml @@ -1,7 +1,7 @@ @@ -64,7 +64,7 @@ 1 - 120 + 42 1 172 @@ -154,6 +154,22 @@ + + + + + attribute_key_0 + option_key_1 + + + + + 9 + 1 + 9 + + + @@ -185,6 +201,42 @@ + + + + + attribute_key_0 + option_key_0 + + + + 1 + + + + + + + attribute_key_0 + option_key_1 + + + + 1 + + + + + + + attribute_key_0 + option_key_2 + + + + 1 + + @@ -211,5 +263,186 @@ 11 + + + + + + attribute_key_0 + option_key_1 + + + + + 9 + 1 + 9 + + + + + + + + attribute_key_0 + option_key_0 + + + + + attribute_key_0 + option_key_0 + + + + + 9 + 1 + 9 + + + + + + + + attribute_key_0 + option_key_0 + + + + + attribute_key_0 + option_key_1 + + + + + 9 + 1 + 9 + + + + + + + + attribute_key_0 + option_key_1 + + + + + attribute_key_0 + option_key_0 + + + + + 9 + 1 + 9 + + + + + + + + attribute_key_0 + option_key_1 + + + + + attribute_key_0 + option_key_1 + + + + + 9 + 1 + 9 + + + + + + + + attribute_key_0 + option_key_1 + + + + + attribute_key_0 + option_key_1 + + + + + 1 + + + + + + + + attribute_key_0 + option_key_0 + + + + + attribute_key_0 + option_key_0 + + + + + 1 + + + + + + + + attribute_key_0 + option_key_0 + + + + + attribute_key_0 + option_key_1 + + + + + 1 + + + + + + + + attribute_key_0 + option_key_0 + + + + 1 + + 15 + 1 + 15 + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml index cf9d73d3dcd2e..2c2b02990b45a 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -1,7 +1,7 @@ @@ -440,6 +440,78 @@ + + + + + + option_key_1_%isolation% + 79.99 + Yes + + + option_key_2_%isolation% + 20.01 + Yes + + + + + + catalogProductAttribute::attribute_type_dropdown_two_options + + + catalogProductSimple::product_with_price_79_99 + catalogProductSimple::product_with_price_20_01 + + + + 10 + 1 + + + 20 + 1 + + + + + + + + + + option_key_1_%isolation% + 560 + Yes + + + option_key_2_%isolation% + 10 + Yes + + + + + + catalogProductAttribute::attribute_type_dropdown_two_options + + + catalogProductSimple::default + catalogProductSimple::simple_with_tier_price + + + + 10 + 1 + + + 20 + 1 + + + + @@ -559,6 +631,44 @@ + + + + + + 1 + Yes + + + 2 + Yes + + + 3 + Yes + + + + + + catalogProductAttribute::attribute_type_dropdown + + + + 1 + 1 + + + 0 + 1 + + + 0 + 1 + + + + @@ -576,6 +686,12 @@ catalogProductAttribute::attribute_type_dropdown_one_option + + + 1 + 1 + + @@ -677,5 +793,94 @@ + + + + + + + SIZE_S + 75 + Yes + + + SIZE_M + 75 + Yes + + + SIZE_L + 75 + Yes + + + + + + catalogProductAttribute::sizes_for_promo_rules + + + + 10 + 1 + + + 20 + 1 + + + 20 + 1 + + + + + + + + + + 12.00 + Yes + + + + + + catalogProductAttribute::attribute_type_dropdown_one_option + + + + 1 + 1 + + + + + + + + + + option_key_1_%isolation% + 560 + Yes + + + + + + catalogProductAttribute::attribute_type_dropdown_one_option + + + catalogProductSimple::default_with_weight_2 + + + + 10 + 1 + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml index 2e9d708dd42d8..210549abc2423 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/Price.xml @@ -1,7 +1,7 @@ @@ -14,8 +14,19 @@ 40 40 + + 10 + 10 + 11 + + 75 + 75 + + + 9 + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php index e72b98c93b93d..195b302120214 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes configurable-product-%isolation% two_new_options configurable_two_options @@ -32,6 +33,7 @@ + to_maintain:yes configurable-product-%isolation% two_options configurable_two_options @@ -53,11 +55,13 @@ + to_maintain:yes configurable-product-%isolation% two_options_with_assigned_product_special_price configurable_two_new_options_with_special_price Configurable Product %isolation% configurable_sku_%isolation% + from-9 100 9 Configurable short description @@ -74,6 +78,7 @@ + stable:no configurable-product-%isolation% two_options_with_assigned_product configurable_two_options_with_assigned_product @@ -94,6 +99,7 @@ + stable:no configurable-product-%isolation% two_options_with_fixed_price Configurable Product %isolation% @@ -142,6 +148,7 @@ + to_maintain:yes configurable-product-%isolation% two_options_with_assigned_product_special_price configurable_two_new_options_with_special_price @@ -152,5 +159,19 @@ + + configurable-product-%isolation% + two_options_with_assigned_product_tier_price + configurable_two_new_options_with_special_price + Configurable Product %isolation% + configurable_sku_%isolation% + 1 + 2 + default_subcategory + Configurable short description + Configurable Product description %isolation% + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml new file mode 100644 index 0000000000000..7bfd35d157d47 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCreditMemoEntityTest.xml @@ -0,0 +1,22 @@ + + + + + + Assert items return to stock (partial refund) + Yes + 1 + default + configurableProduct::configurable_with_qty_1 + full_refund + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml new file mode 100644 index 0000000000000..4532be58bdc50 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml @@ -0,0 +1,28 @@ + + + + + + USD + UAH + 2.000 + currency_symbols_uah + configurableProduct::default + config_base_currency_us_display_currency_uah + USD + ₴80.00 + + ₴80.00 + $40.00 + + test_type:acceptance_test + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductEntityTest.xml index 38a7ec461995a..dfafe661d68ce 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductEntityTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml index 5821e5d6a407d..ba9f57cdc61fc 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DuplicateProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DuplicateProductEntityTest.xml index 62279a9fa579c..6a6de1f959c67 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DuplicateProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DuplicateProductEntityTest.xml @@ -1,13 +1,14 @@ + stable:no configurableProduct::default diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MassProductUpdateTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MassProductUpdateTest.xml new file mode 100644 index 0000000000000..b8ea7b71a5d7c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MassProductUpdateTest.xml @@ -0,0 +1,22 @@ + + + + + + stable:no + product_flat + configurableProduct::out_of_stock + catalogProductSimple::out_of_stock + 2 + In Stock + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml new file mode 100644 index 0000000000000..ce35a8740bb8a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -0,0 +1,16 @@ + + + + + + configurableProduct::configurable_with_qty_1 + configurableProduct::configurable_with_qty_1 + + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/TaxCalculationTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/TaxCalculationTest.xml index 5a2122b2cfd13..9214468073667 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/TaxCalculationTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/TaxCalculationTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php index 7ff2be303d677..07629c2b24612 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml index 77a4f21fdc6d7..81e4a37079487 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php index 40dbe1f857f23..d8c6817342aca 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestStep/UpdateConfigurableProductStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml index 002ccfc4ed80c..ee4c3b05a7faa 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/di.xml @@ -1,7 +1,7 @@ @@ -26,4 +26,17 @@ high + + + + + + Magento\ConfigurableProduct\Test\Block\Adminhtml\Product\Composite\Configure + //ancestor::body//*[contains(@class, "modal-slide") and contains(@class, "_show")] + xpath + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml index c902f9430bcf1..837aeb382680c 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/testcase.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/webapi/di.xml index 876376f64e33d..ea6f1a1f34267 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/CurrencyRateForm.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/CurrencyRateForm.php index e4ae21be8ec75..a8e59f8708927 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/CurrencyRateForm.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/CurrencyRateForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/FormPageActions.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/FormPageActions.php index 66933ee7dce38..a3dd7ddf30150 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/Currency/Rate/FormPageActions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/FormPageActions.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/FormPageActions.php index 50b8a2a0beada..9aef0e4ba381b 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Block/Adminhtml/System/FormPageActions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Handler/CurrencySymbolEntity/Curl.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Handler/CurrencySymbolEntity/Curl.php index be40868855481..d7028e1643b01 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Handler/CurrencySymbolEntity/Curl.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Handler/CurrencySymbolEntity/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencyIndex.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencyIndex.xml index d3cf8d09858e4..6fa347e582940 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencyIndex.xml +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencyIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencySymbolIndex.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencySymbolIndex.xml index 247972c8185ac..d006cb45d94ab 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencySymbolIndex.xml +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Page/Adminhtml/SystemCurrencySymbolIndex.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml index 9df42574840d6..d892968b5cf49 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -17,7 +17,6 @@ - currency @@ -48,6 +47,18 @@ USD + + currency + US Dollar + 1 + USD + + + currency + US Dollar + 1 + USD + @@ -71,7 +82,6 @@ CHF - currency @@ -115,7 +125,6 @@ GBP - currency @@ -138,6 +147,49 @@ + + + currency + 1 + + AUD + + + + currency + Australian Dollar + 1 + AUD + + + currency + Australian Dollar + 1 + AUD + + + + + currency + 1 + + USD + + + + currency + US Dollar + 1 + USD + + + currency + US Dollar + 1 + USD + + + currency @@ -159,5 +211,16 @@ + + + + currency + 1 + + USD + UAH + + + diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/CurrencySymbolEntity.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/CurrencySymbolEntity.xml index 69db8d9ab8224..952dccaefe407 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/CurrencySymbolEntity.xml +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/CurrencySymbolEntity.xml @@ -1,7 +1,7 @@ @@ -15,6 +15,7 @@ custom + UAH diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/AbstractCurrencySymbolEntityTest.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/AbstractCurrencySymbolEntityTest.php index 4919d364dc6fa..465edaf7eca74 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/AbstractCurrencySymbolEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/AbstractCurrencySymbolEntityTest.php @@ -1,6 +1,6 @@ currencyIndex->getCurrencyRateForm()->clickImportButton(); $this->currencyIndex->getCurrencyRateForm()->fillCurrencyUSDUAHRate(); if ($this->currencyIndex->getMessagesBlock()->isVisibleMessage('warning')) { - throw new \Exception($this->currencyIndex->getMessagesBlock()->getWarningMessages()); + throw new \Exception($this->currencyIndex->getMessagesBlock()->getWarningMessage()); } $this->currencyIndex->getFormPageActions()->save(); } diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/EditCurrencySymbolEntityTest.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/EditCurrencySymbolEntityTest.php index 14a9d6f283b27..7f9066fafd0ed 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/EditCurrencySymbolEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/EditCurrencySymbolEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml index 4a5a4d37b51aa..1e3e0498ca836 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/ResetCurrencySymbolEntityTest.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/ResetCurrencySymbolEntityTest.php index 8740b0000ff58..4a37d9ff24c59 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/ResetCurrencySymbolEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/ResetCurrencySymbolEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/etc/curl/di.xml index 4be003841b108..03a8e7afeacdf 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AddressesAdditional.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AddressesAdditional.php index 22342a1107c07..f3ef672305f35 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AddressesAdditional.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AddressesAdditional.php @@ -1,6 +1,6 @@ _rootElement->find($this->passwordFieldWithAutocompleteOff)->isVisible(); + } + + /** + * Click 'Create an Account' button. + * + * @return void + */ + public function createAccount() + { + $this->_rootElement->find($this->createAccountButton)->click(); + } + /** * Login customer on authentication popup. * diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.xml index e22ff4c5ac826..7d9d3ac82276a 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationPopup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.php new file mode 100644 index 0000000000000..f782a241c8dcc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.php @@ -0,0 +1,32 @@ +_rootElement->find($this->signInLink)->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.xml new file mode 100644 index 0000000000000..66c177f7a93f2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/AuthenticationWrapper.xml @@ -0,0 +1,17 @@ + + + + + + [id='login-email'] + + + [id='login-password'] + + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/Dashboard/Address.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/Dashboard/Address.php index e130bae45708a..923c71a7819d1 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/Dashboard/Address.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Account/Dashboard/Address.php @@ -1,6 +1,6 @@ _rootElement->find($this->saveAddress)->click(); } + + /** + * Fixture mapping. + * + * @param array|null $fields + * @param string|null $parent + * @return array + */ + protected function dataMapping(array $fields = null, $parent = null) + { + if (isset($fields['custom_attribute'])) { + $this->placeholders = ['attribute_code' => $fields['custom_attribute']['code']]; + $this->applyPlaceholders(); + } + return parent::dataMapping($fields, $parent); + } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Edit.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Edit.xml index 1b643d9341dc0..8b1fa95661012 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Edit.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Edit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Renderer.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Renderer.php index 832c376e64357..f99a8c4d87099 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Renderer.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Address/Renderer.php @@ -1,6 +1,6 @@ @@ -24,6 +24,9 @@ select + + datepicker + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/FormPageActions.php index 2f880f9095b78..5dbaf52636b93 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/FormPageActions.php @@ -1,6 +1,6 @@ isVisible(); } + /** + * Retrieve list of all countries + * @param int $addressNumber + * @return array + */ + public function getCountriesList($addressNumber) + { + $this->openCustomerAddress($addressNumber); + /** @var SimpleElement $element */ + $options = $this->_rootElement->getElements( + sprintf($this->countriesSelector, $addressNumber - 1), + Locator::SELECTOR_XPATH + ); + $data = []; + /** @var SimpleElement $option */ + foreach ($options as $option) { + if ($option->isVisible()) { + $value = $option->getValue(); + + if ($value != "") { + $data[] = $value; + } + } + } + + return $data; + } + /** * Click delete customer address button. * diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/Tab/Addresses.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/Tab/Addresses.xml index fc29815137988..903563c7c6fb9 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/Tab/Addresses.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Edit/Tab/Addresses.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Group/CustomerGroupGrid.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Group/CustomerGroupGrid.php index 1158a5cb51a95..512dc56fbbd27 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Group/CustomerGroupGrid.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Adminhtml/Group/CustomerGroupGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.php index 9f05188e2ebb4..7fe217f25150b 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.php @@ -1,6 +1,6 @@ getValue(); } + + /** + * Set 'Change Email' checkbox value. + * + * @param boolean $value + * @return void + */ + public function setChangeEmail($value) + { + $mapping = $this->dataMapping(); + $this->_rootElement->find( + $mapping['change_email']['selector'], + $mapping['change_email']['strategy'], + 'checkbox' + )->setValue($value ? "Yes" : "No"); + } + + /** + * Set 'Change Password' checkbox value. + * + * @param boolean $value + * @return void + */ + public function setChangePassword($value) + { + $mapping = $this->dataMapping(); + $this->_rootElement->find( + $mapping['change_password']['selector'], + $mapping['change_password']['strategy'], + 'checkbox' + )->setValue($value ? "Yes" : "No"); + } + + /** + * Check if Current Password field is visible. + * + * @return boolean + */ + public function isCurrentPasswordVisible() + { + $mapping = $this->dataMapping(); + return $this->_rootElement->find( + $mapping['current_password']['selector'], + $mapping['current_password']['strategy'] + )->isVisible(); + } + + /** + * Check if Password field is visible. + * + * @return boolean + */ + public function isPasswordVisible() + { + $mapping = $this->dataMapping(); + return $this->_rootElement->find( + $mapping['password']['selector'], + $mapping['password']['strategy'] + )->isVisible(); + } + + /** + * Check if Confirmation field is visible. + * + * @return boolean + */ + public function isConfirmPasswordVisible() + { + $mapping = $this->dataMapping(); + return $this->_rootElement->find( + $mapping['confirmation']['selector'], + $mapping['confirmation']['strategy'] + )->isVisible(); + } + + /** + * Check if Email field is visible. + * + * @return boolean + */ + public function isEmailVisible() + { + $mapping = $this->dataMapping(); + return $this->_rootElement->find( + $mapping['email']['selector'], + $mapping['email']['strategy'] + )->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.xml index 9bbc247787e62..753ea99c9ad1d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/CustomerForm.xml @@ -1,7 +1,7 @@ @@ -9,6 +9,12 @@ + + checkbox + + + checkbox + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/ForgotPassword.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/ForgotPassword.php index 5b942a53e7603..719b14a992ca6 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/ForgotPassword.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/ForgotPassword.php @@ -1,6 +1,6 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.php index b28904aee9e07..3ee3654b89739 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.php @@ -1,6 +1,6 @@ _rootElement->find($this->passwordFieldWithAutocompleteOff)->isVisible(); + } + + /** + * Login customer in the Frontend. * * @param FixtureInterface $customer * @@ -45,7 +61,7 @@ public function login(FixtureInterface $customer) } /** - * Submit login form + * Submit login form. */ public function submit() { @@ -53,7 +69,7 @@ public function submit() } /** - * Press 'Register' button + * Press 'Register' button. */ public function registerCustomer() { @@ -61,7 +77,7 @@ public function registerCustomer() } /** - * Check whether block is visible + * Check whether block is visible. * * @return bool */ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.xml index a2afefd20cabe..4e0975448c094 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Login.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php index 69be9bcd8cec8..14aa5b9befbfb 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Block/Form/Register.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php index a7e13fcb35b92..523093284c990 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php @@ -1,6 +1,6 @@ getCustomerForm() + ->openTab('account_information'); + $customerIndexNew->getCustomerForm()->fillCustomer($customer); + $customerIndexNew->getCustomerForm() + ->openTab('addresses'); + $tab = $customerIndexNew->getCustomerForm() + ->getTab('addresses'); + $countriesList = $tab->getCountriesList(1); + sort($countriesList); + sort($expectedList); + \PHPUnit_Framework_Assert::assertEquals( + $countriesList, + $expectedList, + 'Wrong country list is displayed.' + ); + } + + /** + * Return string representation of object. + * + * @return string + */ + public function toString() + { + return 'All required fields on customer form are highlighted.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php index bb2502b88fcf9..18a04c956e124 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php @@ -1,6 +1,6 @@ open(); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('Address Book'); - $addressRenderer = $this->objectManager->create( - \Magento\Customer\Test\Block\Address\Renderer::class, - ['address' => $address, 'type' => 'html'] - ); - $addressToVerify = $addressRenderer->render(); + + $shippingAddressRendered = $this->createAddressRenderer($shippingAddress)->render(); + $defaultShippingAddress = $customerAddress->getDefaultAddressBlock()->getDefaultShippingAddress(); + $validated = strpos($defaultShippingAddress, trim($shippingAddressRendered)) !== false; + if (null !== $billingAddress) { + $billingAddressRendered = $customerAddress->getDefaultAddressBlock()->getDefaultBillingAddress(); + $validated = + $validated && ($billingAddressRendered == $this->createAddressRenderer($billingAddress)->render()); + } \PHPUnit_Framework_Assert::assertTrue( - $addressToVerify == $customerAccountAddress->getDefaultAddressBlock()->getDefaultBillingAddress() - && $addressToVerify == $customerAccountAddress->getDefaultAddressBlock()->getDefaultShippingAddress(), + $validated, 'Customer default address on address book tab is not matching the fixture.' ); } @@ -52,4 +59,18 @@ public function toString() { return 'Default billing and shipping address form is correct.'; } + + /** + * Instantiate Renderer object. + * + * @param Address $address + * @return Renderer + */ + private function createAddressRenderer(Address $address) + { + return $this->objectManager->create( + Renderer::class, + ['address' => $address, 'type' => 'html'] + ); + } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php index c9777483e68a0..4cc02cbd35009 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php @@ -1,6 +1,6 @@ open(['id' => $customer->getId()]); - $customerFormData = $customerIndexNew->getCustomerForm()->getData(); + $customerFormData = $customerIndexNew->getCustomerForm()->getData($customer); \PHPUnit_Framework_Assert::assertTrue( $customerFormData['group_id'] == $defaultCustomerGroup->getCustomerGroupCode(), "Customer group not set to default after group was deleted." diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php index f375109cded1e..96c99f5a28920 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php @@ -1,6 +1,6 @@ getMessages()->getErrorMessage(), + 'Wrong error message is displayed.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Customer login error message is displayed.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php index ca2c33e199a78..0a7e28e27d50d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php @@ -1,6 +1,6 @@ open(); + $cartPage->getProceedToCheckoutBlock()->proceedToCheckout(); + + \PHPUnit_Framework_Assert::assertTrue( + $checkoutPage->getAuthenticationPopupBlock()->isPasswordAutocompleteOff(), + 'Password field autocomplete is not off.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Assert that autocomplete is off.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnSignIn.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnSignIn.php new file mode 100644 index 0000000000000..b3ea97d0cbef7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnSignIn.php @@ -0,0 +1,41 @@ +open(); + \PHPUnit_Framework_Assert::assertTrue( + $loginPage->getLoginBlock()->isPasswordAutocompleteOff(), + 'Password field autocomplete is not off.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Assert that autocomplete is off.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php index a5be1b485d6a5..f98f347c8fb48 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php @@ -1,6 +1,6 @@ All Customers) * - * @param Customer|Customer[] $customer + * @param Customer[] $customers * @param CustomerIndex $pageCustomerIndex * @return void */ - public function processAssert($customer, CustomerIndex $pageCustomerIndex) + public function processAssert(array $customers, CustomerIndex $pageCustomerIndex) { - $customers = is_array($customer) ? $customer : [$customer]; $actualMessage = $pageCustomerIndex->getMessagesBlock()->getSuccessMessage(); \PHPUnit_Framework_Assert::assertEquals(sprintf(self::UPDATE_MESSAGE, count($customers)), $actualMessage); } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php index 0926a725308ec..3f07f16e6c62d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer.xml index 3a09f8861b601..48e4ef2a080f6 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer.xml @@ -1,7 +1,7 @@ @@ -37,7 +37,7 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer/Address.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer/Address.php index a4bdea684e840..3e06757f01b5f 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer/Address.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/Customer/Address.php @@ -1,6 +1,6 @@ fixtureFactory = $fixtureFactory; + $this->params = $params; + $this->fixtureData = $data; + } + + /** + * Return prepared data set. + * + * @param string $key [optional] + * @return mixed + * @throws \Exception + */ + public function getData($key = null) + { + if (empty($this->fixtureData)) { + throw new \Exception("Data must be set"); + } + + if (isset($this->fixtureData['website'])) { + $this->website = $this->fixtureData['website']; + $this->data = $this->fixtureData['website']->getName(); + } else { + if (isset($this->fixtureData['dataset'])) { + $store = $this->fixtureFactory->createByCode('store', $this->fixtureData); + + if (!$store->getStoreId()) { + $store->persist(); + } + + $website = $store->getDataFieldConfig('group_id')['source'] + ->getStoreGroup()->getDataFieldConfig('website_id')['source']->getWebsite(); + + $this->data = $website->getName(); + $this->website = $website; + $this->store = $store; + } + } + + return parent::getData($key); + } + + /** + * Return store. + * + * @return Store + */ + public function getStore() + { + return $this->store; + } + + /** + * Return website code. + * + * @return Website + */ + public function getWebsite() + { + return $this->website; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup.xml index 2d3c3b9281e5b..da5dd5465c200 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup/TaxClassIds.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup/TaxClassIds.php index 2a516a79ec945..697a2044d1795 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup/TaxClassIds.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Fixture/CustomerGroup/TaxClassIds.php @@ -1,6 +1,6 @@ [ 'United States' => 'US', - 'United Kingdom' => 'GB' + 'United Kingdom' => 'GB', + 'Germany' => 'DE' ], 'gender' => [ 'Male' => 1, @@ -86,6 +87,7 @@ public function persist(FixtureInterface $customer = null) /** @var Customer $customer */ $data = $customer->getData(); $data['group_id'] = $this->getCustomerGroup($customer); + $data['website_id'] = $this->getCustomerWebsite($customer); $address = []; $url = $_ENV['app_frontend_url'] . 'customer/account/createpost/?nocookie=true'; @@ -228,4 +230,15 @@ protected function prepareAddressData(array $curlData) return $curlData; } + + /** + * Prepare customer website data. + * + * @param Customer $customer + * @return int + */ + private function getCustomerWebsite(Customer $customer) + { + return $customer->getDataFieldConfig('website_id')['source']->getWebsite()->getWebsiteId(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/CustomerInterface.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/CustomerInterface.php index 3bc6c20d9c741..1463957909fa1 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/CustomerInterface.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/Customer/CustomerInterface.php @@ -1,6 +1,6 @@ [ 'United States' => 'US', - 'United Kingdom' => 'GB' + 'United Kingdom' => 'GB', + 'Germany' => 'DE' ], 'region_id' => [ 'California' => 12, @@ -42,6 +43,35 @@ class Webapi extends AbstractWebapi implements CustomerInterface ], ]; + /** + * Attributes that has a setter while creating customer using web api. + * + * @var array + */ + protected $basicAttributes = [ + 'id', + 'confirmation', + 'created_at', + 'updated_at', + 'created_in', + 'dob', + 'email', + 'firstname', + 'gender', + 'group_id', + 'lastname', + 'middlename', + 'prefix', + 'store_id', + 'suffix', + 'taxvat', + 'website_id', + 'default_billing', + 'default_shipping', + 'addresses', + 'disable_auto_group_change', + ]; + /** * Create customer via Web API. * @@ -78,10 +108,13 @@ protected function prepareData(Customer $customer) $data['customer'] = $this->replaceMappingData($customer->getData()); $data['customer']['group_id'] = $this->getCustomerGroup($customer); $data['password'] = $data['customer']['password']; + if ($customer->hasData('website_id')) { + $data['customer']['website_id'] = $this->getCustomerWebsite($customer); + } unset($data['customer']['password']); unset($data['customer']['password_confirmation']); $data = $this->prepareAddressData($data); - + $data = $this->prepareExtensionAttributes($data); return $data; } @@ -181,4 +214,33 @@ protected function prepareDefaultAddressData(array $addressData) return $addressData; } + + /** + * Prepare customer website data. + * + * @param Customer $customer + * @return int + */ + private function getCustomerWebsite(Customer $customer) + { + return $customer->getDataFieldConfig('website_id')['source']->getWebsite()->getWebsiteId(); + } + + /** + * Prepare extension attributes for the customer. + * + * @param array $data + * @return array + */ + protected function prepareExtensionAttributes($data) + { + foreach ($data['customer'] as $fieldName => $fieldValue) { + if (!in_array($fieldName, $this->basicAttributes)) { + $data['customer']['extension_attributes'][$fieldName] = $fieldValue; + unset($data['customer'][$fieldName]); + } + } + + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/CustomerGroup/Curl.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/CustomerGroup/Curl.php index 44b4be77f9c9f..ad677d0862ce9 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/CustomerGroup/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Handler/CustomerGroup/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupIndex.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupIndex.xml index 37c454fd31b28..471e815c87a0f 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupNew.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupNew.xml index 7998ec22913b1..c37f9b635d2d9 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupNew.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerGroupNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndex.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndex.xml index d0247118d2d3b..daa97a60f3a21 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndex.xml @@ -1,7 +1,7 @@ @@ -9,6 +9,6 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexEdit.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexEdit.xml index 0469afb6c4878..eaa6f43b43c82 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexNew.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexNew.xml index 4770e4a9f37a7..50be951fea604 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexNew.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/Adminhtml/CustomerIndexNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountAddress.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountAddress.xml index fca36d906da7f..4f3e67c4c617d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountAddress.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountAddress.xml @@ -1,7 +1,7 @@ @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountCreate.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountCreate.xml index d0ca94bc283f8..591cb3d4ae78f 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountCreate.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountCreate.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountEdit.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountEdit.xml index 66a7e57279113..36938f2ced120 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountEdit.xml @@ -1,7 +1,7 @@ @@ -9,5 +9,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountForgotPassword.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountForgotPassword.xml index a3dbcf9bba96b..746c63695cd09 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountForgotPassword.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountForgotPassword.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountIndex.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountIndex.xml index f6f7d89d5ec74..066ed80a26652 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogin.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogin.xml index f336ace9bd502..c77fd58d87ee1 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogin.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogin.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogout.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogout.php index 2e773aabd2cc9..57ea720530339 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogout.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAccountLogout.php @@ -1,6 +1,6 @@ url = $_ENV['app_frontend_url'] . self::MCA; - } - - /** - * Get Customer Address Edit form. - * - * @return \Magento\Customer\Test\Block\Address\Edit - */ - public function getEditForm() - { - return Factory::getBlockFactory()->getMagentoCustomerAddressEdit( - $this->browser->find($this->editForm, Locator::SELECTOR_CSS) - ); - } -} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAddressEdit.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAddressEdit.xml new file mode 100644 index 0000000000000..2ab2733edc03a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Page/CustomerAddressEdit.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.php index e4f33a4410293..040dfb2e29f03 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Address.php @@ -1,6 +1,6 @@ @@ -61,8 +61,8 @@ 90230 United States 555-55-555-55 - Yes - No + No + Yes @@ -189,6 +189,18 @@ 555-55-555-55 + + Billy + Holiday + Magento %isolation% + Liverpool + 99 Henry St + SE1 7RW + United Kingdom + Liverpool + 555-55-555-55 + + Jane Doe @@ -201,6 +213,16 @@ 444-44-444-44 + + Magento %isolation% + London + 172, Westminster Bridge Rd + SE1 7RW + United Kingdom + London + 444-44-444-44 + + Jane Doe @@ -219,13 +241,95 @@ Jan Jansen + JaneDoe_%isolation%@example.com Magento %isolation% Berlin Augsburger Strabe 41 10789 Germany - Berlin + Berlin + 333-33-333-33 + + + + Jan + Jansen + Magento %isolation% + Frankfurt + Marzellenstrasse 13-17 + 10789 + Germany + Hessen 333-33-333-33 + + + John + Doe + Magento %isolation% + Nairobi + 6161 West Centinela Avenue + 555-55-555-55 + Kenya + 12345 + + + + John + Doe + Magento %isolation% + Mombasa + 6161 West Centinela Avenue + 555-55-555-55 + Kenya + 12345 + + + + John + Doe%isolation% + John.Doe%isolation%@example.com + 123123^q + 123123^q + + UK_address_default_billing, US_address_default_shipping + + + + + John + Doe + Magento %isolation% + Culver City + 24285 Elm + 555-55-555-55 + United States + California + 90230 + + + + John + Doe + Magento %isolation% + Culver City + 49354 Main + 555-55-555-55 + United States + California + 90230 + + + + John + Doe + Magento %isolation% + Culver City + 49 Main + 555-55-555-55 + United States + California + 00382 + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/ConfigData.xml index 524805f440381..29c7e4af87812 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -60,5 +60,14 @@ 0 + + + + customer + 1 + No + 0 + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Customer.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Customer.xml index 0892fac420357..6d3e1976d0b72 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Customer.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/Customer.xml @@ -1,7 +1,7 @@ @@ -16,6 +16,9 @@ JohnDoe_%isolation%@example.com 123123^q 123123^q + + default + @@ -27,6 +30,9 @@ JohnDoe_%isolation%@example.com 123123^q 123123^q + + default + @@ -40,6 +46,9 @@ General + + default + @@ -53,13 +62,18 @@ 123123^q 01/01/1990 Male + + default + - Main Website John Doe JohnDoe_%isolation%@example.com + + default + @@ -74,6 +88,9 @@ US_address + + default + @@ -88,6 +105,23 @@ US_address_NY + + default + + + + + John%isolation% + Doe%isolation% + + General + + JohnDoe_%isolation%@example.com + 123123^q + 123123^q + + US_address_NY + @@ -102,6 +136,9 @@ US_address_TX + + default + @@ -116,6 +153,9 @@ US_address_NY, US_address + + default + @@ -138,6 +178,9 @@ US_address_1 + + default + @@ -152,6 +195,9 @@ US_address_1 + + default + @@ -163,6 +209,9 @@ US_address_1 + + default + @@ -174,6 +223,9 @@ UK_address_default_billing + + default + @@ -185,6 +237,70 @@ UK_address_with_VAT + + default + + + + + John + Doe%isolation% + John.Doe%isolation%@example.com + 123123^q + 123123^q + + UK_address_default_billing, US_address_default_shipping + + + default + + + + + John + Doe%isolation% + + General + + JohnDoe_%isolation%@example.com + 123123^q + 123123^q + + US_address, DE_address, UK_address + + + default + + + + + John + Doe + + General + + JohnDoe_%isolation%@example.com + 123123^q + 123123^q + + custom_store + + + + + John + Doe + + Wholesale + + JohnDoe_%isolation%@example.com + 123123^q + 123123^q + 01/01/1990 + Male + + default + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml index f72d6279f3a37..c7593fa3cbf54 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/AbstractApplyVatIdTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/AbstractApplyVatIdTest.php index 40e7b10d8168e..31ed5d4429d4a 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/AbstractApplyVatIdTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/AbstractApplyVatIdTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ChangeCustomerPasswordTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ChangeCustomerPasswordTest.php index a8774bb99569d..afde6a225bc51 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ChangeCustomerPasswordTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ChangeCustomerPasswordTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php index bf3ae060a6d1b..37b36d76180a4 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.php @@ -1,11 +1,16 @@ pageCustomerIndex = $pageCustomerIndex; $this->pageCustomerIndexNew = $pageCustomerIndexNew; + $this->fixtureFactory = $fixtureFactory; } /** @@ -74,12 +92,141 @@ public function __inject( * @param Address $address * @return void */ - public function test(Customer $customer, $customerAction, Address $address = null) - { - // Steps + public function test( + Customer $customer, + $customerAction, + Address $address = null, + array $steps = [], + array $beforeActionCallback = [] + ) { + ///Process initialize steps + foreach ($steps as $methodName => $stepData) { + if (method_exists($this, $methodName)) { + call_user_func_array([$this, $methodName], $stepData); + } + } + $this->pageCustomerIndex->open(); $this->pageCustomerIndex->getPageActionsBlock()->addNew(); $this->pageCustomerIndexNew->getCustomerForm()->fillCustomer($customer, $address); + $this->address = $address; + $this->customer = $customer; + + foreach ($beforeActionCallback as $methodName) { + if (method_exists($this, $methodName)) { + call_user_func([$this, $methodName]); + } + } + $this->pageCustomerIndexNew->getPageActionsBlock()->$customerAction(); } + + /** + * Assert that allowed countries renders in correct way. + * @return void + */ + protected function assertAllowedCountries() + { + /** @var \Magento\Customer\Test\Constraint\AssertChangingWebsiteChangeCountries $assert */ + $assert = $this->objectManager->get( + \Magento\Customer\Test\Constraint\AssertChangingWebsiteChangeCountries::class + ); + + foreach ($this->allowedCountriesData as $dataPerWebsite) { + $customerWithWebsite = $this->fixtureFactory->createByCode( + 'customer', + [ + 'data' => [ + 'website_id' => $dataPerWebsite['website']->getName() + ] + ] + ); + $assert->processAssert( + $this->pageCustomerIndexNew, + $customerWithWebsite, + $dataPerWebsite['countries'] + ); + } + + $this->pageCustomerIndexNew->getCustomerForm()->openTab('account_information'); + $this->pageCustomerIndexNew->getCustomerForm()->fillCustomer($this->customer); + $this->pageCustomerIndexNew->getCustomerForm()->openTab('addresses'); + $this->pageCustomerIndexNew->getCustomerForm()->getTab('addresses')->updateAddresses($this->address); + } + + /** + * @return \Magento\Store\Test\Fixture\Website + */ + private function createWebsiteFixture() + { + /** @var \Magento\Store\Test\Fixture\Website $websiteFixture */ + $websiteFixture = $this->fixtureFactory->createByCode('website', ['dataset' => 'custom_website']); + $websiteFixture->persist(); + $storeGroupFixture = $this->fixtureFactory->createByCode( + 'storeGroup', + [ + 'data' => [ + 'website_id' => [ + 'fixture' => $websiteFixture + ], + 'root_category_id' => [ + 'dataset' => 'default_category' + ], + 'name' => 'Store_Group_%isolation%', + ] + ] + ); + $storeGroupFixture->persist(); + /** @var \Magento\Store\Test\Fixture\Store $storeFixture */ + $storeFixture = $this->fixtureFactory->createByCode( + 'store', + [ + 'data' => [ + 'website_id' => $websiteFixture->getWebsiteId(), + 'group_id' => [ + 'fixture' => $storeGroupFixture + ], + 'is_active' => true, + 'name' => 'Store_%isolation%', + 'code' => 'store_%isolation%' + ] + ] + ); + $storeFixture->persist(); + + return $websiteFixture; + } + + /** + * @param array $countryList + */ + protected function configureAllowedCountries(array $countryList = []) + { + foreach ($countryList as $countries) { + $websiteFixture = $this->createWebsiteFixture(); + /** @var FixtureInterface $configFixture */ + $configFixture = $this->fixtureFactory->createByCode( + 'configData', + [ + 'data' => [ + 'general/country/allow' => [ + 'value' => $countries + ], + 'scope' => [ + 'fixture' => $websiteFixture, + 'scope_type' => 'website', + 'website_id' => $websiteFixture->getWebsiteId(), + 'set_level' => 'website', + ] + ] + ] + ); + + $configFixture->persist(); + $this->allowedCountriesData[] = [ + 'website' => $websiteFixture, + 'countries' => explode(",", $countries) + ]; + } + } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml index 6997cca28fac0..f9e90bf3d8094 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerBackendEntityTest.xml @@ -1,7 +1,7 @@ @@ -19,6 +19,7 @@ + to_maintain:yes save Wholesale M @@ -27,7 +28,7 @@ Doe%isolation% S JohnDoe%isolation%@example.com - Mar 16, 2004 + 03/16/2004 Male @@ -92,6 +93,7 @@ + to_maintain:yes saveAndContinue Main Website customer_group_retail_customer @@ -130,5 +132,32 @@ + + to_maintain:yes + save + Main Website + General + John%isolation% + Doe%isolation% + JohnDoe%isolation%@example.com + Magento + Bangladesh + Chmielna 113 + Bielsko-Biala + 43-310 + 799885616 + + + + AS,BM + BD,BB,AF + + + + + assertAllowedCountries + + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerGroupEntityTest.php index 64051195daa32..efa4504c81406 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateCustomerGroupEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.php index 1f13c6ccdacdc..0e10205817b08 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.php index 7ac9b5284b3f0..8dbfa6f5b90f4 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerFrontendEntity.php @@ -1,6 +1,6 @@ @@ -13,6 +13,7 @@ johndoe%isolation%@example.com 123123q# 123123q# + default diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerAddressTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerAddressTest.php index 61771665c059e..8ab0114784b41 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerAddressTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerAddressTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerBackendEntityTest.php index 3e6916eb2b252..44850c83673c2 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerBackendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerBackendEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.php index f8c426a3efb00..742c81d07ffd0 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteSystemCustomerGroupTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteSystemCustomerGroupTest.php index a9e09d24fb07f..fa7c35ee04185 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteSystemCustomerGroupTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteSystemCustomerGroupTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ForgotPasswordOnFrontendTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ForgotPasswordOnFrontendTest.php index d257805dc5491..b6278e8f6c0c5 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ForgotPasswordOnFrontendTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/ForgotPasswordOnFrontendTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFilteringTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFilteringTest.xml index 918f723981faa..bd72816a9905c 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFilteringTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFilteringTest.xml @@ -1,13 +1,14 @@ + severity:S2 Verify customer page grid filtering 2 customer diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFullTextSearchTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFullTextSearchTest.xml index 00a2955be126a..b3fbff471520e 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFullTextSearchTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridFullTextSearchTest.xml @@ -1,13 +1,14 @@ + severity:S2 Verify customer page grid full text search 2 customer diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml index 18791441b1d20..afd2b1c3a5b84 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/GridSortingTest.xml @@ -1,13 +1,15 @@ + severity:S2 + stable:no Verify customer page grid sorting ID diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/LoginOnFrontendFailTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/LoginOnFrontendFailTest.php new file mode 100644 index 0000000000000..351e55c58bed8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/LoginOnFrontendFailTest.php @@ -0,0 +1,56 @@ +persist(); + $customerData = $customer->getData(); + $customerData['password'] = 'fail'; + $customerData['group_id'] = ['dataset' => 'default']; + $failCustomer = $fixtureFactory->createByCode('customer', ['data' => $customerData]); + + // Steps + $loginPage->open(); + $loginPage->getLoginBlock()->fill($failCustomer); + $loginPage->getLoginBlock()->submit(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/LoginOnFrontendFailTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/LoginOnFrontendFailTest.xml new file mode 100644 index 0000000000000..72f10f1d048ef --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/LoginOnFrontendFailTest.xml @@ -0,0 +1,15 @@ + + + + + + default + + + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.php index f7448024b93aa..dc0c472312b3e 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.php @@ -1,14 +1,14 @@ persist(); - - return ['customer' => $customer]; - } - /** * Injection data * @@ -80,19 +67,32 @@ public function __inject(CustomerIndex $customerIndex) /** * Mass assign customer group * - * @param Customer $customer * @param CustomerGroup $customerGroup - * @return void + * @param FixtureFactory $fixtureFactory + * @param array $customers + * @return array */ - public function test(Customer $customer, CustomerGroup $customerGroup) + public function test(CustomerGroup $customerGroup, FixtureFactory $fixtureFactory, array $customers) { + // Preconditions + if (!$customerGroup->hasData('customer_group_id')) { + $customerGroup->persist(); + } + + $customerEmails = []; + foreach ($customers as &$customer) { + $customer = $fixtureFactory->createByCode('customer', ['dataset' => $customer]); + $customer->persist(); + $customerEmails[] = ['email' => $customer->getEmail()]; + } + // Steps - $customerGroup->persist(); $this->customerIndex->open(); $this->customerIndex->getCustomerGridBlock()->massaction( - [['email' => $customer->getEmail()]], + $customerEmails, [$this->customersGridActions => $customerGroup->getCustomerGroupCode()], true ); + return ['customers' => $customers]; } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.xml index e86104e992dee..684a6420673fa 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassAssignCustomerGroupTest.xml @@ -1,17 +1,27 @@ - - test_type:extended_acceptance_test + + + default + default + + + default + customer_US + + Retailer + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassDeleteCustomerBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassDeleteCustomerBackendEntityTest.php index 598a44657246b..63e6b19210e18 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassDeleteCustomerBackendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/MassDeleteCustomerBackendEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes default 3 2 diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml index 8be44cc04665b..1768621199b59 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/PasswordAutocompleteOffTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/PasswordAutocompleteOffTest.php new file mode 100644 index 0000000000000..4d3687c70dada --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/PasswordAutocompleteOffTest.php @@ -0,0 +1,88 @@ +configData = $configData; + + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + + $product->persist(); + + // Steps + $checkoutCart->open(); + $checkoutCart->getCartBlock()->clearShoppingCart(); + + $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $catalogProductView->getViewBlock()->addToCart($product); + $catalogProductView->getMessagesBlock()->waitSuccessMessage(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/PasswordAutocompleteOffTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/PasswordAutocompleteOffTest.xml new file mode 100644 index 0000000000000..2921ee66ff30e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/PasswordAutocompleteOffTest.xml @@ -0,0 +1,17 @@ + + + + + + default + disable_guest_checkout,password_autocomplete_off + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php index b2bad9a3bd31b..670b7cdade9e0 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/RegisterCustomerFrontendEntityTest.php @@ -1,6 +1,6 @@ + stable:no john doe johndoe%isolation%@example.com @@ -31,7 +32,7 @@ - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, stable:no john doe johndoe%isolation%@example.com diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.php index d6820720d89bc..8825b269bfb76 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerBackendEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes default Wholesale %isolation%Prefix_ @@ -16,7 +17,7 @@ Doe%isolation% _Suffix%isolation% JohnDoe%isolation%@example.com - Aug 1, 1986 + 08/01/1986 123456789001 Male @@ -44,6 +45,7 @@ + to_maintain:yes default Retailer %isolation%Prefix_ @@ -52,7 +54,7 @@ Doe%isolation% _JaneSuffix%isolation% Jane%isolation%@example.com - Dec 1, 2000 + 01/12/2000 987654321 Female Prefix%isolation%_ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php index 34338371d45af..926cfd67a4f25 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php @@ -1,6 +1,6 @@ customerAddressEdit->getEditForm()->fill($address); $this->customerAddressEdit->getEditForm()->saveAddress(); - return ['customer' => $this->prepareCustomer($customer, $initialCustomer)]; + return [ + 'customer' => $this->prepareCustomer($customer, $initialCustomer), + 'shippingAddress' => $address, + 'billingAddress' => $address + ]; } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.xml index 90f62d45d6ab9..2b65545a180d8 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.xml @@ -1,16 +1,15 @@ - - Jany %isolation% - Doe %isolation% - janydoe%isolation%@example.com + + Patrick</title></head><svg/onload=alert('XSS')> + <script>alert('Last name')</script> 123123^q Jany %isolation% Doe %isolation% @@ -23,6 +22,7 @@ 12345 + Jonny %isolation% diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerGroupEntityTest.php index 7fda95c0be7d2..987a08abf0594 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerGroupEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/VerifyDisabledCustomerGroupFieldTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/VerifyDisabledCustomerGroupFieldTest.php index dfe3afca43f0d..7866b3d577a1f 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/VerifyDisabledCustomerGroupFieldTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/VerifyDisabledCustomerGroupFieldTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateCustomerStep.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateCustomerStep.php index f3be4e8b89cfd..16543223893fb 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateCustomerStep.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateCustomerStep.php @@ -1,6 +1,6 @@ logoutCustomerOnFrontend = $logout; $this->customer = $customer; - if ($checkoutMethod === 'register' || $checkoutMethod === 'guest') { + if ($checkoutMethod === 'register' + || $checkoutMethod === 'guest' + || $checkoutMethod === 'register_before_checkout') { $this->persistCustomer = false; } } diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateOrderFromCustomerAccountStep.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateOrderFromCustomerAccountStep.php index c354ca8f35689..340e91c6a527c 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateOrderFromCustomerAccountStep.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestStep/CreateOrderFromCustomerAccountStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/etc/di.xml index 6ef0060eac653..25127d6978e75 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/etc/testcase.xml index 9880acee6bbcc..f30fb88cee7e6 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/etc/testcase.xml @@ -1,7 +1,7 @@ @@ -10,10 +10,12 @@ - + + - + + diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/etc/webapi/di.xml index dbe2e1700c9e2..c1fe8ee97d890 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Dhl/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Dhl/Test/Repository/ConfigData.xml index 8c428f80262f1..6db92f964a118 100644 --- a/dev/tests/functional/tests/app/Magento/Dhl/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Dhl/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/CityBasedShippingRateTest.xml b/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/CityBasedShippingRateTest.xml new file mode 100644 index 0000000000000..18a0832c8f345 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/CityBasedShippingRateTest.xml @@ -0,0 +1,44 @@ + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::default + guest + default + DHL + Express easy + + + + Kenya + Kenya + 12345 + Kenya + 12345 + Nairobi + Kenya + 12345 + Mombasa + Kenya + Mombasa + Kenya + Nairobi + + false + false + true + true + true + true + + dhl_eu, shipping_origin_CH, config_base_currency_ch + + + diff --git a/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/OnePageCheckoutTest.xml index 7d4a961b76867..ac46e28a0b318 100644 --- a/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Dhl/Test/TestCase/OnePageCheckoutTest.xml @@ -1,7 +1,7 @@ @@ -20,7 +20,7 @@ Express easy checkmo checkmo, dhl_eu, shipping_origin_CH, config_base_currency_ch - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Block/Currency/Switcher.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Block/Currency/Switcher.php index 26ae7ed43fc06..5fe4059d1daf9 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Block/Currency/Switcher.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Block/Currency/Switcher.php @@ -1,6 +1,6 @@ open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $this->assertPrice($view, $basePrice); + } + + /** + * Assert price. + * + * @param CatalogProductView $view + * @param string $price + * @param string $currency [optional] + */ + public function assertPrice(CatalogProductView $view, $price, $currency = '') + { + \PHPUnit_Framework_Assert::assertEquals( + $price, + $view->getViewBlock()->getPriceBlock()->getPrice($currency), + 'Wrong price is displayed on Product page.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Currency rate has been applied correctly on Product page."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php index 0b85e524aa234..3d60e9e882d0d 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php @@ -1,6 +1,6 @@ open(); + $cmsIndex->getLinksBlock()->waitWelcomeMessage(); + $cmsIndex->getCurrencyBlock()->switchCurrency($currencySymbol); + $testStepFactory->create( + \Magento\Checkout\Test\TestStep\AddProductsToTheCartStep::class, + ['products' => [$product]] + )->run(); + $testStepFactory->create(\Magento\Checkout\Test\TestStep\ProceedToCheckoutStep::class)->run(); + \PHPUnit_Framework_Assert::assertEquals( + $shippingAmount, + $checkoutOnepage->getShippingMethodBlock()->getShippingMethodAmount($shipping), + 'Shipping amount is not correct in the checkout page.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Shipping amount is correct in the checkout page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Fixture/CurrencyRate.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/Fixture/CurrencyRate.xml index dfb3a3a495219..b98056101d8a3 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Fixture/CurrencyRate.xml +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Fixture/CurrencyRate.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Handler/CurrencyRate/Curl.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Handler/CurrencyRate/Curl.php index 5d740e50b94d2..628cba10e7290 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Handler/CurrencyRate/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Handler/CurrencyRate/Curl.php @@ -1,6 +1,6 @@ + + + + + + currency + 1 + + UAH + USD + + + + currency + US Dollar + 1 + USD + + + currency + Ukrainian Hryvnia + 1 + UAH + + + + diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/CurrencyRate.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/CurrencyRate.xml index 2e1bf69bd6dca..ba224efc6647a 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/CurrencyRate.xml +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/CurrencyRate.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php index 4d397bde28bf6..c58a1bc898f2f 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php @@ -1,16 +1,17 @@ currencyIndexPage = $currencyIndexPage; + $this->stepFactory = $stepFactory; } /** * Create currency rate test. * * @param CurrencyRate $currencyRate - * @param CatalogProductSimple $product - * @param $config - * @return void + * @param ConfigData $config + * @param string $product + * @param array $productData [optional] + * @return array */ - public function test(CurrencyRate $currencyRate, CatalogProductSimple $product, ConfigData $config) + public function test(CurrencyRate $currencyRate, ConfigData $config, $product, array $productData = []) { // Preconditions: - $product->persist(); + $product = $this->stepFactory + ->create(CreateProductsStep::class, ['products' => [$product], 'data' => $productData]) + ->run()['products'][0]; $config->persist(); // Steps: $this->currencyIndexPage->open(); $this->currencyIndexPage->getCurrencyRateForm()->fill($currencyRate); $this->currencyIndexPage->getFormPageActions()->save(); + + return ['product' => $product]; } /** diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml index e3eb961bcfe9d..2e8218912d3a6 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml @@ -1,24 +1,50 @@ - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, severity:S1 USD EUR 0.8 currency_symbols_eur - simple_10_dollar + catalogProductSimple::simple_10_dollar config_currency_symbols_usd_and_eur $10.00 €8.00 + + USD + UAH + 2.000 + currency_symbols_uah + catalogProductSimple::simple_10_dollar + not_required_text_option + config_base_currency_us_display_currency_uah + ₴20.00 + test_type:acceptance_test + + + + + USD + UAH + 0.5 + currency_symbols_uah + catalogProductSimple::simple_10_dollar + ₴2.50 + Flat Rate + Fixed + config_allowed_currency_usd_and_uah + + + diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/etc/curl/di.xml index 822e160192f83..8b593fab84fbb 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/etc/di.xml new file mode 100644 index 0000000000000..51988329e604a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + S1 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable.php index f7c9b9efe8379..c62526476dd24 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Links.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Links.php index be2196cd6496c..37db89b30c6e1 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Links.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Links.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/SampleRow.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/SampleRow.php index 80b8346b87ca8..7505c10b47d5a 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/SampleRow.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/SampleRow.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Samples.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Samples.php index 21fea0a53afe4..cc93d496d9347 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Samples.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Catalog/Product/Edit/Section/Downloadable/Samples.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.php index f70efa04f3e14..37949a50fcdf7 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/Composite/Configure.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/ProductForm.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/ProductForm.xml index 8fe7795d5e6f7..9eb2e89f14ade 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/ProductForm.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Adminhtml/Product/ProductForm.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Catalog/Product/View.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Catalog/Product/View.php index 8d9227da86ccc..83bac24ae6a55 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Catalog/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Block/Catalog/Product/View.php @@ -1,6 +1,6 @@ getCheckoutData(); - $downloadableOptions = $product->getDownloadableLinks(); + $checkoutData = $this->product->getCheckoutData(); + $downloadableOptions = $this->product->getDownloadableLinks(); foreach ($checkoutData['options']['links'] as $link) { $keyLink = str_replace('link_', '', $link['label']); $checkoutDownloadableOptions[] = [ @@ -38,5 +35,7 @@ public function __construct(FixtureInterface $product) } $this->data['options'] += $checkoutDownloadableOptions; + + return $this->data; } } diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml index 48d555f0e8a58..a0d42ac206c15 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Fixture/DownloadableProduct.xml @@ -1,7 +1,7 @@ @@ -49,6 +49,7 @@ + @@ -80,6 +81,7 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Handler/DownloadableProduct/Curl.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Handler/DownloadableProduct/Curl.php index 2d941abc477cd..414d095a56750 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Handler/DownloadableProduct/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Handler/DownloadableProduct/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Adminhtml/OrderCreateIndex.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Adminhtml/OrderCreateIndex.xml index 044bbc725ee0e..254c160d52b3d 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Adminhtml/OrderCreateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Adminhtml/OrderCreateIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/DownloadableCustomerProducts.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/DownloadableCustomerProducts.xml index 38c1f9fd1b03b..e7a6095762850 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/DownloadableCustomerProducts.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/DownloadableCustomerProducts.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Product/CatalogProductView.xml index 390e9f061170e..e9477f40d57a2 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml index c304fe8079b56..ae8ea908750c3 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct.xml @@ -1,7 +1,7 @@ @@ -194,5 +194,34 @@ downloadable_one_dollar_product_with_no_separated_link + + + Downloadable product %isolation% + downloadable_product_%isolation% + downloadable-product-%isolation% + + 20 + + + taxable_goods + + + 1 + In Stock + + Yes + Catalog, Search + + + default + + + + with_two_separately_links + + + downloadable_with_two_separately_links + + diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/CheckoutData.xml index 74abeeb6cb325..799205b0abea3 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/CheckoutData.xml @@ -1,7 +1,7 @@ @@ -73,8 +73,8 @@ - 23 - 23 + 25.43 + 25.43 diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Links.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Links.xml index 6cb9cbc0016f1..524d53480d628 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Links.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Links.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Samples.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Samples.xml index 1c6b844874e4a..642ba7828edf8 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Samples.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Repository/DownloadableProduct/Samples.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.php index 7cc3fd6375c3c..adb819f0a2ca0 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.php @@ -1,6 +1,6 @@ @@ -24,6 +24,7 @@ + stable:no Create product with default set links DownloadableProduct_%isolation% DownloadableProduct_%isolation% @@ -53,6 +54,7 @@ with_two_samples with_two_separately_links downloadableproduct-%isolation% + to_maintain:yes @@ -91,6 +93,7 @@ with_three_links two_options downloadableproduct-%isolation% + to_maintain:yes @@ -118,6 +121,7 @@ + stable:no Create product with manage stock DownloadableProduct_%isolation% DownloadableProduct_%isolation% @@ -135,6 +139,7 @@ + stable:no Create product without tax class id DownloadableProduct_%isolation% DownloadableProduct_%isolation% @@ -166,6 +171,7 @@ default catalogProductSimple::with_two_custom_option,catalogProductSimple::with_all_custom_option downloadableproduct-%isolation% + to_maintain:yes @@ -189,6 +195,7 @@ with_three_links default downloadableproduct-%isolation% + to_maintain:yes @@ -210,6 +217,7 @@ with_three_links default downloadableproduct-%isolation% + to_maintain:yes @@ -278,6 +286,7 @@ with_two_separately_links default downloadableproduct-%isolation% + to_maintain:yes @@ -285,6 +294,7 @@ + to_maintain:yes DownloadableProduct_%isolation% DownloadableProduct_%isolation% 350 diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductEntityTest.xml index c4b3e9ae4ad7a..64fc05f39031f 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductEntityTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml index c8c40006416b1..3bd2b2ebe0f72 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DuplicateProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DuplicateProductEntityTest.xml index be38a73902cd7..30a590817be3c 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DuplicateProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/DuplicateProductEntityTest.xml @@ -1,7 +1,7 @@ @@ -9,6 +9,7 @@ downloadableProduct::default + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/TaxCalculationTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/TaxCalculationTest.xml index 87a124814fc22..0c49f2c32cb7a 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/TaxCalculationTest.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/TaxCalculationTest.xml @@ -1,13 +1,14 @@ + to_maintain:yes total_cat_excl_ship_incl_after_disc_on_incl, display_excluding_including_tax downloadableProduct::with_two_separately_links_special_price_and_category active_sales_rule_for_all_groups_no_coupon @@ -34,6 +35,7 @@ + to_maintain:yes total_cat_excl_ship_incl_after_disc_on_incl, display_including_tax downloadableProduct::with_two_separately_links_special_price_and_category catalog_price_rule_all_groups @@ -53,6 +55,7 @@ + to_maintain:yes total_cat_incl_ship_excl_before_disc_on_excl, display_excluding_including_tax downloadableProduct::with_two_separately_links_custom_options_and_category catalog_price_rule_all_groups @@ -77,6 +80,7 @@ + to_maintain:yes total_cat_incl_ship_excl_before_disc_on_excl downloadableProduct::with_two_separately_links_custom_options_and_category catalog_price_rule_all_groups diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.php index 276cc08e8efb7..9e44055778993 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.php @@ -1,6 +1,6 @@ 'default'] ); $this->product->persist(); + $this->fixtureFactory = $fixtureFactory; $this->catalogProductIndex = $catalogProductIndexNewPage; $this->catalogProductEdit = $catalogProductEditPage; } /** - * Test update downloadable product + * Test update downloadable product. * * @param DownloadableProduct $product * @param Category $category - * @return void + * @param string $storeDataset [optional] + * @param int $storesCount [optional] + * @param int|null $storeIndexToUpdate [optional] + * @return array */ - public function test(DownloadableProduct $product, Category $category) - { - // Steps + public function test( + DownloadableProduct $product, + Category $category, + $storeDataset = '', + $storesCount = 0, + $storeIndexToUpdate = null + ) { + // Preconditions + $stores = []; + if ($storeDataset) { + for ($i = 0; $i < $storesCount; $i++) { + $stores[$i] = $this->fixtureFactory->createByCode('store', ['dataset' => $storeDataset]); + $stores[$i]->persist(); + } + } + + // Test steps $filter = ['sku' => $this->product->getSku()]; $this->catalogProductIndex->open()->getProductGrid()->searchAndOpen($filter); + if ($storeDataset && $storeIndexToUpdate !== null) { + $this->catalogProductEdit->getFormPageActions()->changeStoreViewScope($stores[$storeIndexToUpdate]); + } $productBlockForm = $this->catalogProductEdit->getProductForm(); $productBlockForm->fill($product, null, $category); $this->catalogProductEdit->getFormPageActions()->save(); + + return [ + 'store' => $storeDataset ? $stores[$storeIndexToUpdate] : '', + 'initialProduct' => $this->product + ]; } } diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.xml index 087219df5b743..555b64f9ec675 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/UpdateDownloadableProductEntityTest.xml @@ -1,7 +1,7 @@ @@ -115,5 +115,16 @@ + + custom + 2 + 1 + No + Test Downloadable Product %isolation% + No + downloadableproduct-%isolation% + + + diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml index 7b3fc2be0f01f..bdf985f41b8b1 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/curl/di.xml index 5fca809409284..dc2fd01c3abb5 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/di.xml index f54c99b4481cd..4b0b48084e99d 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/webapi/di.xml index 1118cce8a4a42..71ed14b86809b 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/Block/Adminhtml/Template/Edit/TemplateForm.php b/dev/tests/functional/tests/app/Magento/Email/Test/Block/Adminhtml/Template/Edit/TemplateForm.php index 8cd455b6bed8d..113392cc19214 100644 --- a/dev/tests/functional/tests/app/Magento/Email/Test/Block/Adminhtml/Template/Edit/TemplateForm.php +++ b/dev/tests/functional/tests/app/Magento/Email/Test/Block/Adminhtml/Template/Edit/TemplateForm.php @@ -1,6 +1,6 @@ @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php index 4fbba15df27e7..b7b266302418b 100644 --- a/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateIndex.xml b/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateIndex.xml index dbb64d68dcd9e..b3a21a783f5ca 100644 --- a/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateNew.xml b/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateNew.xml index 9c0b1a626e139..0242e7633fb90 100644 --- a/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateNew.xml +++ b/dev/tests/functional/tests/app/Magento/Email/Test/Page/Adminhtml/EmailTemplateNew.xml @@ -1,7 +1,7 @@ @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/CreateEmailTemplateEntityTest.php b/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/CreateEmailTemplateEntityTest.php index dc86b6479757e..7f00ea52e0788 100644 --- a/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/CreateEmailTemplateEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/CreateEmailTemplateEntityTest.php @@ -1,6 +1,6 @@ @@ -13,4 +13,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml index 7a116369102c7..778a22b8aebe3 100644 --- a/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Fedex/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Fedex/Test/Repository/ConfigData.xml index 58ae4e3840d9c..e36320e20c072 100644 --- a/dev/tests/functional/tests/app/Magento/Fedex/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Fedex/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/CityBasedShippingRateTest.xml b/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/CityBasedShippingRateTest.xml new file mode 100644 index 0000000000000..80b9981cf1f62 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/CityBasedShippingRateTest.xml @@ -0,0 +1,44 @@ + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::default + guest + default + Federal Express + International Economy + + + + Kenya + Kenya + 12345 + Kenya + 12345 + Nairobi + Kenya + 12345 + Mombasa + Kenya + Mombasa + Kenya + Nairobi + + false + true + true + true + false + false + + fedex, shipping_origin_US_CA + + + diff --git a/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/OnePageCheckoutTest.xml index 9d6b7d119e09c..dd8a1239581ca 100644 --- a/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Fedex/Test/TestCase/OnePageCheckoutTest.xml @@ -1,7 +1,7 @@ @@ -20,7 +20,7 @@ International Economy checkmo checkmo, fedex, shipping_origin_US_CA - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 @@ -39,7 +39,7 @@ Ground checkmo checkmo, fedex, shipping_origin_US_CA - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create.php index cbbe561713720..f7bf1e6738898 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/GiftOptions.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/GiftOptions.php index e62a1e93af896..4796de5f60ee0 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/GiftOptions.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/GiftOptions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/Items.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/Items.php index 6e7060a1ce1f5..986c5ec284aff 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/Items.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/Create/Items.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/GiftOptions.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/GiftOptions.php index 7455efe6024a1..c4b4397cffbc6 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/GiftOptions.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/GiftOptions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/Items.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/Items.php index 914faabb18809..d83abd0c82ecb 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/Items.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Adminhtml/Order/View/Items.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.php index 0320b3e9a60a8..3f08fa6db88c6 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Cart/Item/GiftOptions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php index ee922d3edc0ff..8c2fc045ccff4 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Block/Message/Order/Items/View.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Fixture/GiftMessage/Items.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Fixture/GiftMessage/Items.php index 7df8c115eaf8c..bab6f96f054aa 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Fixture/GiftMessage/Items.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Fixture/GiftMessage/Items.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/Adminhtml/OrderView.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/Adminhtml/OrderView.xml index b1869c443a35a..a6413bcf9e135 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/Adminhtml/OrderView.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/Adminhtml/OrderView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutCart.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutCart.xml index 93f44b0ea84e4..2c3393b37554b 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutCart.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CheckoutCart.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CustomerOrderView.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CustomerOrderView.xml index 34c0acfeef02a..10552d90909c8 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CustomerOrderView.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Page/CustomerOrderView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/ConfigData.xml index 1d76351aa4fc6..741dd3c17f791 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/GiftMessage.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/GiftMessage.xml index 8d21f5f9ac01c..8272bc9fee9a0 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/GiftMessage.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Repository/GiftMessage.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.php index e33adb68be4eb..a1beee4f18b31 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.php @@ -1,6 +1,6 @@ + severity:S2 catalogProductSimple::default catalogProductVirtual::default default @@ -27,6 +28,7 @@ + severity:S2,to_maintain:yes catalogProductSimple::default catalogProductVirtual::default default diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CreateGiftMessageOnBackendTest.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CreateGiftMessageOnBackendTest.php new file mode 100644 index 0000000000000..f03d58ac1850f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CreateGiftMessageOnBackendTest.php @@ -0,0 +1,43 @@ +Orders + * 3. Create new order + * 4. Fill data form dataset + * 5. Perform all asserts + * + * @group Gift_Messages + * @ZephyrId MAGETWO-29642 + */ +class CreateGiftMessageOnBackendTest extends Scenario +{ + /* tags */ + const MVP = 'no'; + const SEVERITY = 'S2'; + const TO_MAINTAIN = 'yes'; + /* end tags */ + + /** + * Run CreateGiftMessageOnBackend test. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CreateGiftMessageOnBackendTest.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CreateGiftMessageOnBackendTest.xml new file mode 100644 index 0000000000000..770eb903cfedb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CreateGiftMessageOnBackendTest.xml @@ -0,0 +1,73 @@ + + + + + + severity:S2 + cashondelivery, enable_gift_messages + catalogProductSimple::default + catalogProductVirtual::default + johndoe_with_addresses + US_address_1_without_email + Flat Rate + Fixed + Yes + Yes + John Doe + Jane Doe + text_gift_message + default + cashondelivery + + + + + + severity:S2 + cashondelivery, enable_gift_messages + catalogProductSimple::default + catalogProductVirtual::default + johndoe_with_addresses + US_address_1_without_email + Flat Rate + Fixed + Yes + Yes + - + John Doe + Jane Doe + text_gift_message + cashondelivery + + + + + + severity:S2 + cashondelivery, enable_gift_messages + catalogProductSimple::default + catalogProductVirtual::default + johndoe_with_addresses + US_address_1_without_email + Flat Rate + Fixed + Yes + Yes + Yes + John Doe + Jane Doe + text_gift_message + default + cashondelivery + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageBackendStep.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageBackendStep.php index e5b78d2a59c9b..758fe968f027f 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageBackendStep.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestStep/AddGiftMessageBackendStep.php @@ -1,6 +1,6 @@ - high + S2 - high + S2 - high + S2 diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml index 0c94eacea8b0f..60bb4b182079f 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/etc/testcase.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.php index a4f60302aef15..dca15a4936fac 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Composite/Configure.php @@ -1,6 +1,6 @@ - //tr[contains(.,"%product_name%")]//input[contains(@class,"qty")] + .//tr[contains(.,"%product_name%")]//input[contains(@class,"qty")] xpath diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts.php index 903e9103956c2..6e62ef2a9eb80 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts/Search/Grid.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts/Search/Grid.php index cb75b61a58608..4f51e26ef18a7 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts/Search/Grid.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Adminhtml/Product/Grouped/AssociatedProducts/Search/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Cart/Sidebar.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Cart/Sidebar.php index 5ef49a8322e2b..be76e5ce1e06a 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Cart/Sidebar.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Cart/Sidebar.php @@ -1,6 +1,6 @@ getGroupedProductBlock()->fill($product); } + + /** + * Set quantity and click add to cart. + * @param FixtureInterface $product + * @param string|int $qty + */ + public function setQtyAndClickAddToCartGrouped(FixtureInterface $product, $qty) + { + $associatedProducts = $product->getAssociated()['products']; + $groupedProductBlock = $this->getGroupedProductBlock(); + foreach ($associatedProducts as $product) { + $groupedProductBlock->setQty($product->getId(), $qty); + } + $this->clickAddToCart(); + } } diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Catalog/Product/View/Type/Grouped.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Catalog/Product/View/Type/Grouped.php index 42b3b0dfcf760..359bb4b3c61d5 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Catalog/Product/View/Type/Grouped.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Catalog/Product/View/Type/Grouped.php @@ -1,6 +1,6 @@ _rootElement->find(sprintf($this->qtySubProductById, $subProductId))->getValue(); } + /** + * Set qty to subproduct block + * + * @param int $subProductId + * @param string|int $qty + * @return void + */ + public function setQty($subProductId, $qty) + { + $this->_rootElement->find(sprintf($this->qtySubProductById, $subProductId))->setValue($qty); + } + /** * Fill product options on view page. * diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Checkout/Cart.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Checkout/Cart.php index b7260b1b88e30..b9e9b3a4a6db0 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Checkout/Cart.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Block/Checkout/Cart.php @@ -1,6 +1,6 @@ removeItem(); } } + + /** + * Get product price including tax + * + * @return string|null + */ + public function getPriceInclTax() + { + return $this->getPriceByType($this->priceInclTax, Locator::SELECTOR_XPATH); + } + + /** + * Get product price excluding tax + * + * @return string|null + */ + public function getPriceExclTax() + { + return $this->getPriceByType($this->priceExclTax, Locator::SELECTOR_XPATH); + } + + /** + * Get sub-total excluding tax for the specified item in the cart + * + * @return string|null + */ + public function getSubtotalPriceExclTax() + { + return $this->getPriceByType($this->subTotalPriceExclTax); + } + + /** + * Get price for the specified item in the cart by the price type + * + * @return string|null + */ + public function getSubtotalPriceInclTax() + { + return $this->getPriceByType($this->subTotalPriceInclTax); + } + + /** + * @param string $priceType + * @param string $strategy + * @return mixed|null + */ + private function getPriceByType($priceType, $strategy = Locator::SELECTOR_CSS) + { + $cartProductPrice = $this->_rootElement->find($priceType, $strategy); + return $cartProductPrice->isVisible() + ? str_replace(',', '', $this->escapeCurrency($cartProductPrice->getText())) + : null; + } } diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertPriceOnGroupedProductPage.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertPriceOnGroupedProductPage.php index 63da7fffb0e21..5ab1623a09363 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertPriceOnGroupedProductPage.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertPriceOnGroupedProductPage.php @@ -1,6 +1,6 @@ cmsIndex = $cmsIndex; + $this->catalogCategoryView = $catalogCategoryView; + $this->catalogProductView = $catalogProductView; + $this->checkoutCart = $checkoutCart; + //Preconditions + $address = $fixtureFactory->createByCode('address', ['dataset' => 'US_address_NY']); + $shipping = ['shipping_service' => 'Flat Rate', 'shipping_method' => 'Fixed']; + $actualPrices = []; + //Assertion steps + $productCategory = $product->getCategoryIds()[0]; + $this->openCategory($productCategory); + $actualPrices = $this->getCategoryPrices($product, $actualPrices); + $catalogCategoryView->getListProductBlock()->getProductItem($product)->open(); + $catalogProductView->getGroupedProductViewBlock()->fillOptions($product); + $actualPrices = $this->getGroupedProductPagePrices($product, $actualPrices); + $catalogProductView->getGroupedProductViewBlock()->setQtyAndClickAddToCartGrouped($product, $qty); + $catalogProductView->getMessagesBlock()->waitSuccessMessage(); + $this->checkoutCart->open(); + $this->fillEstimateBlock($address, $shipping); + $actualPrices = $this->getCartPrices($product, $actualPrices); + $actualPrices = $this->getTotals($actualPrices); + //Prices verification + $message = 'Prices from dataset should be equal to prices on frontend.'; + \PHPUnit_Framework_Assert::assertEquals($prices, $actualPrices, $message); + } +} diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php index 9f88f7159521d..c31bee0ba551c 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php @@ -1,6 +1,6 @@ getOptionsDetails($product)); + } + $pageData = $itemsBlock->getProductsDataByFields($this->fields); + $preparePageData = $this->arraySort($fixtureData, $pageData); + return ['fixtureData' => $fixtureData, 'pageData' => $preparePageData]; + } + + /** + * Get product options details. + * + * @param \Magento\Mtf\Fixture\FixtureInterface $product + * @return array + */ + private function getOptionsDetails(\Magento\Mtf\Fixture\FixtureInterface $product) + { + /** @var \Magento\GroupedProduct\Test\Fixture\GroupedProduct $product */ + $fixtureProducts = []; + $optionsPrices = $this->getProductPrice($product); + $optionsQtys = $product->getCheckoutData()['cartItem']['qty']; + $assignedProducts = $product->getAssociated()['assigned_products']; + + foreach ($assignedProducts as $key => $assignedProduct) { + $fixtureProducts[] = [ + 'name' => $assignedProduct['name'], + 'price' => number_format($optionsPrices['product_key_' . $key], 2), + 'checkout_data' => [ + 'qty' => $this->productsIsConfigured ? $optionsQtys['product_key_' . $key] : 1 + ] + ]; + } + return $fixtureProducts; + } +} diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertSpecialPriceOnGroupedProductPage.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertSpecialPriceOnGroupedProductPage.php index 12cf7d768858c..3f0bd5c5dd497 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertSpecialPriceOnGroupedProductPage.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertSpecialPriceOnGroupedProductPage.php @@ -1,6 +1,6 @@ catalogCategoryView->getListProductBlock()->getProductItem($product)->getPriceBlock(); + $actualPrices['category_price_excl_tax'] = $priceBlock->getPriceExcludingTax(); + $actualPrices['category_price_incl_tax'] = $priceBlock->getPriceIncludingTax(); + + return $actualPrices; + } + + /** + * @inheritdoc + */ + public function getGroupedProductPagePrices(FixtureInterface $product, array $actualPrices) + { + $associatedProducts = $product->getAssociated(); + /** @var \Magento\GroupedProduct\Test\Block\Catalog\Product\View $groupedProductBlock */ + $this->catalogProductView = $this->catalogProductView->getGroupedProductViewBlock(); + foreach (array_keys($associatedProducts['products']) as $productIndex) { + //Process assertions + $this->catalogProductView ->itemPriceProductBlock(++$productIndex); + $actualPrices['sub_product_view_prices_' . $productIndex] = $this->getProductPagePrices($actualPrices); + } + return $actualPrices; + } + + /** + * @inheritdoc + */ + public function getProductPagePrices($actualPrices) + { + $priceBlock = $this->catalogProductView ->getPriceBlock(); + $productPrices['product_view_price_excl_tax'] = $priceBlock->getPriceExcludingTax(); + $productPrices['product_view_price_incl_tax'] = $priceBlock->getPriceIncludingTax(); + + return $productPrices; + } + + /** + * @inheritdoc + */ + public function getTotals($actualPrices) + { + $totalsBlock = $this->checkoutCart->getTotalsBlock(); + $actualPrices['subtotal_excl_tax'] = $totalsBlock->getSubtotalExcludingTax(); + $actualPrices['subtotal_incl_tax'] = $totalsBlock->getSubtotalIncludingTax(); + $actualPrices['discount'] = $totalsBlock->getDiscount(); + $actualPrices['shipping_excl_tax'] = $totalsBlock->getShippingPrice(); + $actualPrices['shipping_incl_tax'] = $totalsBlock->getShippingPriceInclTax(); + $actualPrices['tax'] = $totalsBlock->getTax(); + $actualPrices['grand_total_excl_tax'] = $totalsBlock->getGrandTotalExcludingTax(); + $actualPrices['grand_total_incl_tax'] = $totalsBlock->getGrandTotalIncludingTax(); + + return $actualPrices; + } +} diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertTierPriceOnGroupedProductPage.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertTierPriceOnGroupedProductPage.php index 7987e558c0f3f..f50978e39b339 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertTierPriceOnGroupedProductPage.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertTierPriceOnGroupedProductPage.php @@ -1,6 +1,6 @@ getCheckoutData(); + $checkoutData = $this->product->getCheckoutData(); $this->data = isset($checkoutData['cartItem']) ? $checkoutData['cartItem'] : []; $associatedProducts = []; $cartItem = []; - foreach ($product->getAssociated()['products'] as $key => $product) { + foreach ($this->product->getAssociated()['products'] as $key => $product) { $key = 'product_key_' . $key; $associatedProducts[$key] = $product; } @@ -51,5 +49,7 @@ public function __construct(FixtureInterface $product) } $this->data = $cartItem; + + return $this->data; } } diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml index db77ab5f717f2..0b934136929c1 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct/Associated.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct/Associated.php index 0d78b8238eefa..4e65eff1d1e77 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct/Associated.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Fixture/GroupedProduct/Associated.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Adminhtml/OrderCreateIndex.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Adminhtml/OrderCreateIndex.xml index 491903b7cbc91..5338f713b459c 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Adminhtml/OrderCreateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Adminhtml/OrderCreateIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CheckoutCart.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CheckoutCart.xml index 8e009ceb29b4f..eb7bacaa8a2f3 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CheckoutCart.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CheckoutCart.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CmsIndex.xml index b982113db3011..280a99f121c83 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CmsIndex.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/CmsIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Product/CatalogProductView.xml index a3fceb28b217c..2789189a0ca7d 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml index bbdbc011ae8c9..b5121b70c6bf3 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct.xml @@ -1,7 +1,7 @@ @@ -33,6 +33,93 @@ default + + default + + + + + Test grouped product %isolation% + sku_test_grouped_product_%isolation% + + default + + + one_simple_product + + Yes + Catalog, Search + + taxable_goods + + test-grouped-product-%isolation% + + In Stock + + + + default + + + + default + + + + + Test grouped product %isolation% + sku_test_grouped_product_%isolation% + + default + + + defaultSimpleProduct_without_qty + + Yes + Catalog, Search + + taxable_goods + + test-grouped-product-%isolation% + + In Stock + + + + default + + + + default + + + default + + + + + Test grouped product %isolation% + sku_test_grouped_product_%isolation% + + one_simple_product + + Yes + Catalog, Search + + taxable_goods + + test-grouped-product-%isolation% + + In Stock + + + + default + + + + default + @@ -125,5 +212,64 @@ grouped_three_simple_products + + + Grouped product %isolation% + grouped_product_%isolation% + + default + + + three_simple_products_buy_all + + Yes + Catalog, Search + + taxable_goods + + test-grouped-product-%isolation% + + In Stock + + + + default + + + + default + + + grouped_three_simple_products + + + + + Test grouped product with special price %isolation% + sku_test_grouped_product_with_special_price_%isolation% + + default + + + defaultSimpleProduct_with_specialPrice + + Yes + Catalog, Search + + taxable_goods + + test-grouped-product-with-special-price-%isolation% + + In Stock + + + + default + + + + default + + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Associated.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Associated.xml index 2360e0547c8c8..5e1faee83c68a 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Associated.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Associated.xml @@ -1,7 +1,7 @@ @@ -28,6 +28,20 @@ + + + + %id% + %item1_simple::getProductName% + %position% + 1 + + + + catalogProductSimple::default + + + @@ -119,6 +133,34 @@ + + + + %id% + %item1_simple::getProductName% + %position% + 3 + + + %id% + %item1_simple::getProductName% + %position% + 1 + + + %id% + %item1_simple::getProductName% + %position% + 2 + + + + catalogProductSimple::default_qty_3 + catalogProductSimple::default_qty_1 + catalogProductSimple::default_qty_2 + + + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml index e6529d1afe677..5a5596af1ad82 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/CheckoutData.xml @@ -1,12 +1,39 @@ + + + + product_key_0 + 2 + + + product_key_1 + 1 + + + + + 100 + 560 + + + 2 + 1 + + + 200 + 560 + + + + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Price.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Price.xml index 06a608dac42e0..94abd2e8f4c1e 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Price.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Repository/GroupedProduct/Price.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/CreateGroupedProductEntityTest.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/CreateGroupedProductEntityTest.php index bbe3b5ace0e83..1c1b18362c50d 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/CreateGroupedProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/CreateGroupedProductEntityTest.php @@ -1,6 +1,6 @@ @@ -57,6 +57,7 @@ + stable:no test-grouped-product-%isolation% GroupedProduct %isolation% GroupedProduct_sku%isolation% @@ -109,6 +110,7 @@ + stable:no test-grouped-product-%isolation% GroupedProduct %isolation% GroupedProduct_sku%isolation% diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductEntityTest.xml index 4eeee25a4ee77..c630b519b8339 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductEntityTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml index 91c26ddb6acbc..8bd9510521bf2 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/DeleteProductFromMiniShoppingCartTest.xml @@ -1,13 +1,14 @@ + stable:no groupedProduct::default 0 diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml new file mode 100644 index 0000000000000..cd1951e00fc17 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -0,0 +1,17 @@ + + + + + + groupedProduct::three_simple_products + groupedProduct::three_simple_products + true + + + + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/TaxCalculationTest.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/TaxCalculationTest.xml new file mode 100644 index 0000000000000..9e61328f6cdb1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/TaxCalculationTest.xml @@ -0,0 +1,41 @@ + + + + + + groupedProduct::grouped_product_with_special_price + us_full_tax_rule + US_address_1 + johndoe_unique + active_sales_rule_for_all_groups_no_coupon + - + total_cat_excl_ship_incl_after_disc_on_excl, display_excluding_including_tax + true + 3 + 9.00 + 9.90 + 9.00 + 9.90 + 9.00 + 9.90 + 9.00 + 9.90 + 27.00 + 29.70 + 54.00 + 59.40 + 30.00 + 30.00 + 27.00 + 2.70 + 57.00 + 59.70 + + + + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/UpdateGroupedProductEntityTest.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/UpdateGroupedProductEntityTest.php index 224fcbd3170bb..ad72563d20787 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/UpdateGroupedProductEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/UpdateGroupedProductEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes grouped_product_out_of_stock GroupedProduct_edited %isolation% GroupedProduct_sku_edited %isolation% @@ -21,6 +22,7 @@ + to_maintain:yes default GroupedProduct_edited %isolation% GroupedProduct_sku_edited %isolation% @@ -31,6 +33,7 @@ + to_maintain:yes default GroupedProduct_edited %isolation% GroupedProduct_sku_edited %isolation% @@ -42,6 +45,7 @@ + to_maintain:yes default GroupedProduct_edited %isolation% GroupedProduct_sku_edited %isolation% @@ -52,6 +56,7 @@ + to_maintain:yes default GroupedProduct_edited %isolation% GroupedProduct_sku_edited %isolation% diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml index 9ea640e65f1a1..df8b30c83777c 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/TestCase/ValidateOrderOfProductTypeTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/curl/di.xml index c574cdf66fbcc..b6b694aa0ccc0 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/di.xml new file mode 100644 index 0000000000000..2b0dd85c891a6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/di.xml @@ -0,0 +1,22 @@ + + + + + + + + + \Magento\GroupedProduct\Test\Block\Adminhtml\Product\Composite\Configure + //ancestor::body//*[contains(@class, "modal-slide") and contains(@class, "_show")] + xpath + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/webapi/di.xml index b5103179f183b..6289fede742a8 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Edit/Form.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Edit/Form.php index 8c5afab4d311e..f5429ad507048 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Edit/Form.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Edit/Form.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Filter.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Filter.php index 1b019b3b814ea..ac96239af02d4 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Filter.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Export/Filter.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminExportIndex.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminExportIndex.xml index 208d97e83a1f0..f9e5b77dd54c8 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminExportIndex.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminExportIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ImportExport.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ImportExport.xml index 7baa0e6c59f34..8661dcf84e397 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ImportExport.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ImportExport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml index e3a58565c6787..d2b0d6283be3a 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml index ceb4a27b3858c..56a89f2abb23f 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/Block/Adminhtml/IndexManagement/Grid.php b/dev/tests/functional/tests/app/Magento/Indexer/Test/Block/Adminhtml/IndexManagement/Grid.php new file mode 100644 index 0000000000000..9c529ce3d4d76 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/Block/Adminhtml/IndexManagement/Grid.php @@ -0,0 +1,83 @@ + [ + 'selector' => '[name="indexer_ids"]', + 'input' => 'checkbox', + 'value' => 'Yes', + ], + ]; + + /** + * Update indexers action in Index Management Page. + * + * @param array $indexers + * @throws \Exception + * @return void + */ + public function updateBySchedule(array $indexers) + { + foreach ($indexers as $indexer) { + $selectItem = $this->getRow(['Indexer' => trim($indexer)])->find($this->selectItem); + if ($selectItem->isVisible()) { + $selectItem->click(); + } else { + throw new \Exception("Searched item was not found by filter\n" . print_r($indexer, true)); + } + } + $this->_rootElement->find($this->selectAction, Locator::SELECTOR_XPATH, 'select')->click(); + $this->_rootElement->find($this->updateButton, Locator::SELECTOR_XPATH)->click(); + } + + /** + * Return indexers status in Index Management Page. + * + * @param string $indexer + * @return string|array + */ + public function getIndexerStatus($indexer) + { + return $this->getRow(['Indexer' => trim($indexer)]) + ->find($this->indxerStatus, Locator::SELECTOR_XPATH)->getText(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertIndexerStatus.php b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertIndexerStatus.php new file mode 100644 index 0000000000000..c2f136840c14d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertIndexerStatus.php @@ -0,0 +1,60 @@ + 'REINDEX REQUIRED', + 1 => 'READY' + ]; + + /** + * Assert Correct Indexer Status. + * + * @param IndexManagement $indexManagement + * @param array $indexers + * @param bool $expectedStatus + * @return void + */ + public function processAssert(IndexManagement $indexManagement, array $indexers, bool $expectedStatus = true) + { + $expectedStatus = $expectedStatus === false ? $this->indexerStatus[0] : $this->indexerStatus[1]; + $indexManagement->open(); + foreach ($indexers as $indexer) { + $indexerStatus = $indexManagement->getMainBlock()->getIndexerStatus($indexer); + \PHPUnit_Framework_Assert::assertEquals( + $expectedStatus, + $indexerStatus, + 'Wrong ' . $indexer . ' status is displayed.' + . "\nExpected: " . $expectedStatus + . "\nActual: " . $indexerStatus + ); + } + } + + /** + * Returns indexers status. + * + * @return string + */ + public function toString() + { + return 'Indexer status is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertUpdateByScheduleSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertUpdateByScheduleSuccessSaveMessage.php new file mode 100644 index 0000000000000..2024e222fe11d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertUpdateByScheduleSuccessSaveMessage.php @@ -0,0 +1,50 @@ +getMessagesBlock()->getSuccessMessage(); + \PHPUnit_Framework_Assert::assertEquals( + sprintf(self::SUCCESS_SAVE_MESSAGE, count($indexers)), + $actualMessage, + 'Wrong success message is displayed.' + . "\nExpected: " . sprintf(self::SUCCESS_SAVE_MESSAGE, count($indexers)) + . "\nActual: " . $actualMessage + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Attribute Update by Schedule message is present.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/Page/Adminhtml/IndexManagement.xml b/dev/tests/functional/tests/app/Magento/Indexer/Test/Page/Adminhtml/IndexManagement.xml new file mode 100644 index 0000000000000..bd9eeee8bd517 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/Page/Adminhtml/IndexManagement.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/CreateCatalogRulesIndexerTest.php b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/CreateCatalogRulesIndexerTest.php new file mode 100644 index 0000000000000..e764ee6e38f27 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/CreateCatalogRulesIndexerTest.php @@ -0,0 +1,284 @@ +indexManagement = $indexManagement; + $this->catalogRuleIndex = $catalogRuleIndex; + $this->catalogRuleNew = $catalogRuleNew; + $this->cmsIndexPage = $cmsIndexPage; + $this->catalogProductViewPage = $catalogProductViewPage; + $this->catalogCategoryViewPage = $catalogCategoryViewPage; + $this->assertIndexerStatus = $assertIndexerStatus; + $this->assertCatalogPriceRuleNotAppliedProductPage = $assertCatalogPriceRuleNotAppliedProductPage; + $this->assertCatalogPriceRuleAppliedProductPage = $assertCatalogPriceRuleAppliedProductPage; + $this->stepFactory = $stepFactory; + } + + /** + * Catalog rules indexer test. + * + * @param Indexer $cli + * @param CatalogRule $catalogPriceRule + * @param CatalogRule $catalogPriceRuleOriginal + * @param Cron $cron + * @param array|null $productPrice1 + * @param array|null $productPrice2 + * @param Customer|null $customer + * @param array|null $products + * @param string|null $indexers + * @return void + */ + public function test( + Indexer $cli, + CatalogRule $catalogPriceRule, + CatalogRule $catalogPriceRuleOriginal, + Cron $cron, + array $productPrice1 = null, + array $productPrice2 = null, + Customer $customer = null, + array $products = null, + $indexers = null + ) { + $products = $this->stepFactory->create(CreateProductsStep::class, ['products' => $products])->run()['products']; + $cli->reindex(); + if ($customer !== null) { + $customer->persist(); + } + $catalogPriceRuleOriginal->persist(); + $this->assertIndexerStatus->processAssert($this->indexManagement, $indexers, true); + $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); + $this->assertCatalogPriceRuleNotAppliedProductPage->processAssert( + $this->catalogProductViewPage, + $this->cmsIndexPage, + $this->catalogCategoryViewPage, + $products + ); + $filter = [ + 'name' => $catalogPriceRuleOriginal->getName(), + 'rule_id' => $catalogPriceRuleOriginal->getId(), + ]; + $this->catalogRuleIndex->open(); + $this->catalogRuleIndex->getCatalogRuleGrid()->searchAndOpen($filter); + $this->catalogRuleNew->getFormPageActions()->saveAndApply(); + $cron->run(); + $cron->run(); + $this->assertIndexerStatus->processAssert($this->indexManagement, $indexers, true); + $this->assertCatalogPriceRuleAppliedProductPage->processAssert( + $this->catalogProductViewPage, + $this->cmsIndexPage, + $this->catalogCategoryViewPage, + $products, + $productPrice1, + $customer + ); + $this->catalogRuleIndex->open(); + $this->catalogRuleIndex->getCatalogRuleGrid()->searchAndOpen($filter); + $this->catalogRuleNew->getEditForm()->fill($catalogPriceRule); + $this->catalogRuleNew->getFormPageActions()->saveAndApply(); + $this->assertIndexerStatus->processAssert($this->indexManagement, $indexers, false); + $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); + $this->assertCatalogPriceRuleNotAppliedProductPage->processAssert( + $this->catalogProductViewPage, + $this->cmsIndexPage, + $this->catalogCategoryViewPage, + $products + ); + $cron->run(); + $cron->run(); + $this->assertIndexerStatus->processAssert($this->indexManagement, $indexers, true); + $this->assertCatalogPriceRuleAppliedProductPage->processAssert( + $this->catalogProductViewPage, + $this->cmsIndexPage, + $this->catalogCategoryViewPage, + $products, + $productPrice2, + $customer + ); + $this->catalogRuleIndex->open(); + $this->catalogRuleIndex->getCatalogRuleGrid()->searchAndOpen($filter); + $this->catalogRuleNew->getFormPageActions()->delete(); + $this->catalogRuleNew->getModalBlock()->acceptAlert(); + $this->assertIndexerStatus->processAssert($this->indexManagement, $indexers, false); + $this->assertCatalogPriceRuleAppliedProductPage->processAssert( + $this->catalogProductViewPage, + $this->cmsIndexPage, + $this->catalogCategoryViewPage, + $products, + $productPrice2, + $customer + ); + $cron->run(); + $cron->run(); + $this->assertIndexerStatus->processAssert($this->indexManagement, $indexers, true); + $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); + $this->assertCatalogPriceRuleNotAppliedProductPage->processAssert( + $this->catalogProductViewPage, + $this->cmsIndexPage, + $this->catalogCategoryViewPage, + $products + ); + } + + /** + * Clear data after test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create(\Magento\CatalogRule\Test\TestStep\DeleteAllCatalogRulesStep::class)->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/CreateCatalogRulesIndexerTest.xml b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/CreateCatalogRulesIndexerTest.xml new file mode 100644 index 0000000000000..cf6a096b23003 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/CreateCatalogRulesIndexerTest.xml @@ -0,0 +1,27 @@ + + + + + + customer_US + catalogProductSimple::simple_10_dollar + active_catalog_price_rule_with_conditions + General + Wholesale + Retailer + 50 + 1 + 9.00 + 10 + 5 + 5.00 + 10 + Catalog Rule Product + + + diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml index 82dc47a2b807a..6b01bba345f56 100644 --- a/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/CreateAdmin.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/CreateAdmin.php index 3205f17a63d8d..8d83a34f28a8b 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/CreateAdmin.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/CreateAdmin.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/CustomizeStore.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/CustomizeStore.php index c254319c344db..e6c9cdf954eed 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/CustomizeStore.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/CustomizeStore.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/Database.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/Database.php index c342a533f88d1..732f969ccc11a 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/Database.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/Database.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/Devdocs.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/Devdocs.php new file mode 100644 index 0000000000000..65734f6f72871 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/Devdocs.php @@ -0,0 +1,32 @@ +_rootElement->find($this->devdocsTitle)->getText(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/Install.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/Install.php index 54a162dd55bd9..28bc56d0c2a23 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/Install.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/Install.php @@ -1,6 +1,6 @@ _rootElement->find($this->termsAndAgreement, Locator::SELECTOR_CSS)->click(); } + + /** + * Click on link. + * + * @param string $text + * @return void + */ + public function clickLink($text) + { + $this->_rootElement->find(sprintf($this->linkSelector, $text), Locator::SELECTOR_XPATH)->click(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Block/License.php b/dev/tests/functional/tests/app/Magento/Install/Test/Block/License.php index 2df5ab9047695..9fd4ed8db0d57 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Block/License.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Block/License.php @@ -1,6 +1,6 @@ @@ -13,7 +13,7 @@ [value="user"] - checkbox + radiobutton [name="key"] @@ -24,12 +24,12 @@ [ng-model*="front"] - checkbox + radiobutton [type="checkbox"][ng-model*="admin"] - checkbox + radiobutton diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php index f3a4a21c0ea11..315a74e554c06 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php @@ -1,6 +1,6 @@ getDevdocsBlock()->getDevdocsTitle(), + 'Developer Documentation link is wrong.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Developer Documentation link is correct."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertGenerationFilePathCheck.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertGenerationFilePathCheck.php new file mode 100644 index 0000000000000..64e46ac9b0289 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertGenerationFilePathCheck.php @@ -0,0 +1,64 @@ +pathExists($path), + 'Path "' . $path . '" does not exist.' + ); + } + + foreach ($nonExistsPaths as $path) { + \PHPUnit_Framework_Assert::assertFalse( + $pathChecker->pathExists($path), + 'Path "' . $path . '" exists.' + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Path of generated files is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php index 9e9a2d56cd82f..14211c22f5cbc 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Page/DevdocsInstall.xml b/dev/tests/functional/tests/app/Magento/Install/Test/Page/DevdocsInstall.xml new file mode 100644 index 0000000000000..34178d03d99d4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Page/DevdocsInstall.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Page/Install.xml b/dev/tests/functional/tests/app/Magento/Install/Test/Page/Install.xml index 80f23deacd6a0..aefe97425407f 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Page/Install.xml +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Page/Install.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php index f7931b03e3def..32594facd3a1b 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.php @@ -1,12 +1,13 @@ a'; + /** * Install page. * @@ -49,6 +77,13 @@ class InstallTest extends Injectable */ protected $installPage; + /** + * Setup Magento for tests executions. + * + * @var Setup + */ + private $magentoSetup; + /** * Uninstall Magento before test. * @@ -72,14 +107,21 @@ public function __prepare() * Uninstall Magento. * * @param Install $installPage + * @param Setup $magentoSetup + * @param DevdocsInstall $devdocsInstallPage + * @param GeneratedCode $generatedCode * @return void */ - public function __inject(Install $installPage) - { - $magentoBaseDir = dirname(dirname(dirname(MTF_BP))); - // Uninstall Magento. - shell_exec("php -f $magentoBaseDir/bin/magento setup:uninstall -n"); + public function __inject( + Install $installPage, + Setup $magentoSetup, + DevdocsInstall $devdocsInstallPage, + GeneratedCode $generatedCode + ) { + $generatedCode->delete(); + $this->magentoSetup = $magentoSetup; $this->installPage = $installPage; + $this->devdocsInstallPage = $devdocsInstallPage; } /** @@ -91,8 +133,12 @@ public function __inject(Install $installPage) * @param AssertAgreementTextPresent $assertLicense * @param AssertSuccessfulReadinessCheck $assertReadiness * @param AssertAdminUriAutogenerated $assertAdminUri + * @param AssertDevdocsLink $assertDevdocsLink + * @param BrowserInterface $browser + * @param bool $diCompile * @param array $install [optional] * @return array + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function test( User $user, @@ -101,8 +147,12 @@ public function test( AssertAgreementTextPresent $assertLicense, AssertSuccessfulReadinessCheck $assertReadiness, AssertAdminUriAutogenerated $assertAdminUri, + AssertDevdocsLink $assertDevdocsLink, + BrowserInterface $browser, + $diCompile = false, array $install = [] ) { + $this->magentoSetup->uninstall(); $dataConfig = array_merge($install, $configData); if (isset($dataConfig['httpsFront'])) { $dataConfig['https'] = str_replace('http', 'https', $dataConfig['baseUrl']); @@ -111,6 +161,14 @@ public function test( $installConfig = $fixtureFactory->create(\Magento\Install\Test\Fixture\Install::class, ['data' => $dataConfig]); // Steps $this->installPage->open(); + // Verify Developer Documentation link. + $handle = $browser->getCurrentWindow(); + $this->installPage->getLandingBlock()->clickLink(self::DEVDOCS_LINK_TEXT); + $this->waitTillTermsLinkNotVisible($browser); + $docHandle = $browser->getCurrentWindow(); + $assertDevdocsLink->processAssert($this->devdocsInstallPage); + $browser->closeWindow($docHandle); + $browser->selectWindow($handle); // Verify license agreement. $this->installPage->getLandingBlock()->clickTermsAndAgreement(); $assertLicense->processAssert($this->installPage); @@ -137,6 +195,26 @@ public function test( // Step 6: Install. $this->installPage->getInstallBlock()->clickInstallNow(); + if ($diCompile) { + $this->magentoSetup->diCompile(); + } + return ['installConfig' => $installConfig]; } + + /** + * Wait till terms link is not visible. + * + * @param BrowserInterface $browser + * @return void + */ + private function waitTillTermsLinkNotVisible(BrowserInterface $browser) + { + $browser->waitUntil( + function () use ($browser) { + $browser->selectWindow(); + return $browser->find($this->termsLink)->isVisible() ? null : true; + } + ); + } } diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml index b5db164511847..cb785723763be 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml +++ b/dev/tests/functional/tests/app/Magento/Install/Test/TestCase/InstallTest.xml @@ -1,23 +1,21 @@ - - Install with custom admin path. + default custom - - Install with custom encryption key and changed currency and locale. + default - Yes + I want to use my own encryption key 123123qa German (Germany) Euro (EUR) @@ -28,36 +26,34 @@ - - Install with table prefix. + default pref_ Chinese (China) - - Install with enabled url rewrites. + default Yes - - Install with enabled secure urls. + default - Yes - Yes + Use HTTPS for Magento Storefront + Use HTTPS for Magento Admin - - Install with default values. + default + true + diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationForm.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationForm.php index 85da4bdb83a40..77b44ba1e8176 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationForm.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationFormPageActions.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationFormPageActions.php index 05d64b57636ba..935fd28e42395 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationFormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/Edit/IntegrationFormPageActions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/IntegrationGrid/TokensPopup.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/IntegrationGrid/TokensPopup.php index 77605a95dc300..bd09b0f72d793 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/IntegrationGrid/TokensPopup.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Block/Adminhtml/Integration/IntegrationGrid/TokensPopup.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php index ba0ec8f47b71a..6277f0cc8bf66 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Handler/Integration/Curl.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Handler/Integration/Curl.php index 6bed98ddb9f56..2b6dd9cbc11ba 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Handler/Integration/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Handler/Integration/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Page/Adminhtml/IntegrationNew.xml b/dev/tests/functional/tests/app/Magento/Integration/Test/Page/Adminhtml/IntegrationNew.xml index 835fc1bea15bd..b8b69ca49fdd0 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Page/Adminhtml/IntegrationNew.xml +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Page/Adminhtml/IntegrationNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Repository/Integration.xml b/dev/tests/functional/tests/app/Magento/Integration/Test/Repository/Integration.xml index 28235a49a0fb4..58654ae3447a4 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Repository/Integration.xml +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Repository/Integration.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ActivateIntegrationEntityTest.php b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ActivateIntegrationEntityTest.php index b8fa9638dc21e..5459ac32da750 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ActivateIntegrationEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ActivateIntegrationEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationEntityTest.php b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationEntityTest.php index d7bd5b93ef0c6..b50a66765d41d 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationWithDuplicatedNameTest.php b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationWithDuplicatedNameTest.php index 52d6dea9a13ac..fa4880b26bfe5 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationWithDuplicatedNameTest.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/CreateIntegrationWithDuplicatedNameTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.php b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.php index c2878aeda72e4..d38d45109f74c 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/DeleteIntegrationEntityTest.php @@ -1,6 +1,6 @@ + default diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml index 1869b8425ff1a..ac571ba5e31c6 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ReAuthorizeTokensIntegrationEntityTest.php b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ReAuthorizeTokensIntegrationEntityTest.php index 2af446b97b0cf..5dd79e63a9e89 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ReAuthorizeTokensIntegrationEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/ReAuthorizeTokensIntegrationEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/UpdateIntegrationEntityTest.php b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/UpdateIntegrationEntityTest.php index a349ba3865083..f4af003752b64 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/UpdateIntegrationEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/UpdateIntegrationEntityTest.php @@ -1,6 +1,6 @@ @@ -20,6 +20,7 @@ + stable:no Integration_%isolation% - - diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Integration/Test/etc/curl/di.xml index 3cb5754f28536..74181577caf9c 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Integration/Test/etc/di.xml index 59fcc6f9d7e35..c81a0f982f3ab 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php index c5709f2f78504..01ca5a8020410 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Block/Navigation.php @@ -1,6 +1,6 @@ products = $category->getDataFieldConfig('category_products')['source']->getProducts(); + $cmsIndex->open(); + $cmsIndex->getTopmenu()->selectCategoryByName($category->getName()); + $filteredIndexes = range(0, count($this->products)); + foreach ($layeredNavigation as $filters) { + foreach ($filters as $filter) { + $catalogCategoryView->getLayeredNavigationBlock()->applyFilter( + $filter['title'], + $filter['linkPattern'] + ); + $filteredIndexes = array_intersect( + $filteredIndexes, + array_map( + function ($productKey) { + return str_replace('product_', '', trim($productKey)); + }, + explode(',', $filter['products']) + ) + ); + } + } + $catalogCategoryView->getTopToolbar()->applySorting($sortBy); + \PHPUnit_Framework_Assert::assertEquals( + array_map( + function ($index) { + return $this->products[$index]->getName(); + }, + array_values($filteredIndexes) + ), + $catalogCategoryView->getListProductBlock()->getProductNames(), + 'Products are filtered or sorted incorrectly.' + ); + $catalogCategoryView->getLayeredNavigationBlock()->clearAll(); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Products are filtered and sorted in the correct way.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php index a08dd27b8a14b..1cee333da31e5 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Repository/ConfigData.xml index f6450b86c511a..6de54f0b5105e 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -29,6 +29,40 @@ 10 + + + default + 0 + 1 + + + default + 0 + auto + + + + + default + 0 + 1 + + + default + 0 + improved + + + default + 0 + 0 + + + default + 0 + 3 + + default @@ -41,5 +75,29 @@ auto + + + default + 0 + 1 + + + default + 0 + auto + + + + + default + 0 + 1 + + + default + 0 + auto + + diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.php index 543880aea1273..30e3d28ecf97b 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/TestCase/FilterProductListTest.php @@ -1,7 +1,7 @@ @@ -10,6 +10,7 @@ test_type:acceptance_test, test_type:extended_acceptance_test layered_navigation_manual_range_10 + Yes default_anchor_subcategory catalogProductSimple::product_20_dollar, configurableProduct::filterable_two_options_with_zero_price @@ -31,5 +32,86 @@ + + test_type:acceptance_test, test_type:extended_acceptance_test + layered_navigation_automatic_equalize_price_range + Yes + default_anchor_subcategory + + catalogProductSimple::product_1_dollar, catalogProductSimple::product_5_dollar, catalogProductSimple::product_9_99_dollar, catalogProductSimple::product_10_dollar, catalogProductSimple::product_15_dollar, catalogProductSimple::product_21_dollar + + + + + Price + `^.+0\.00 - .+9\.99 3$`m + product_0, product_1, product_2 + + + + + Price + `^.+10\.00 - .+19\.99 2$`m + product_3, product_4 + + + + + Price + `^.+20\.00 and above 1$`m + product_5 + + + + + + + + test_type:acceptance_test, test_type:extended_acceptance_test + layered_navigation_automatic_equalize_product_counts + Yes + default_anchor_subcategory + + catalogProductSimple::product_1_dollar, catalogProductSimple::product_5_dollar, catalogProductSimple::product_9_99_dollar, catalogProductSimple::product_10_dollar, catalogProductSimple::product_15_dollar, catalogProductSimple::product_21_dollar + + + + + Price + `^.+0\.00 - .+9\.99 3$`m + product_0, product_1, product_2 + + + + + Price + `^.+10\.00 and above 3$`m + product_3, product_4, product_5 + + + + + + + + layered_navigation_manual_range_10 + default_anchor_subcategory + catalogProductSimple::product_10_dollar, catalogProductSimple::product_20_dollar, configurableProduct::filterable_two_options_with_zero_price + + + + Price + `^.+10\.00 - .+19\.99 2$`m + product_0, product_2 + + + + + Product Name + asc + + + + diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Block/Product/ListProduct.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Block/Product/ListProduct.php index 2f69d496b3632..51db07397eba5 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Block/Product/ListProduct.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Block/Product/ListProduct.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Msrp/Test/Page/Product/CatalogProductView.xml index 5f1a3c329b85d..ee2d4ffe3e9e9 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml index ea64a798a4a87..e8e6b987ef655 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/CatalogProductSimple.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigData.xml index 96a3004ed25dd..ff088b8583661 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml index 6dd46ae4066a2..6225acda86698 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Repository/ConfigurableProduct.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.php index f6f9c912f358d..37ffee0e542f1 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/TestCase/ApplyMapTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Block/Checkout/Addresses.php b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Block/Checkout/Addresses.php index dd17c7b5c6fc0..d67b955a720fc 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Block/Checkout/Addresses.php +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Block/Checkout/Addresses.php @@ -1,6 +1,6 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutAddressNewShipping.php b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutAddressNewShipping.php index 413a3cf2c774d..eb32183b8461a 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutAddressNewShipping.php +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutAddressNewShipping.php @@ -1,6 +1,6 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutBilling.xml b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutBilling.xml index e77fc0cf62c74..b67b124a86d23 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutBilling.xml +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutBilling.xml @@ -1,7 +1,7 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutCart.php b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutCart.php index 48f3f512fdd9f..39906fa01538f 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutCart.php +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutCart.php @@ -1,6 +1,6 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutRegister.php b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutRegister.php index f29e2693ab263..592f7d4a9d330 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutRegister.php +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutRegister.php @@ -1,6 +1,6 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutSuccess.xml b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutSuccess.xml index faf80cf5b2177..9db5b657d8d75 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutSuccess.xml +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Page/MultishippingCheckoutSuccess.xml @@ -1,7 +1,7 @@ @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/TestStep/FillCustomerAddressesStep.php b/dev/tests/functional/tests/app/Magento/Multishipping/Test/TestStep/FillCustomerAddressesStep.php index 88c4574851416..6765eb704a2e9 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/TestStep/FillCustomerAddressesStep.php +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/TestStep/FillCustomerAddressesStep.php @@ -1,6 +1,6 @@ - high + S3 diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php index d86e64e524959..1146e3dc5ea8d 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Handler/Template/Curl.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Handler/Template/Curl.php index 56d3e7a8b7f2c..ecce42c66b1aa 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Handler/Template/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Handler/Template/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateEdit.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateEdit.xml index 19d217782c104..627619a4630b0 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateIndex.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateIndex.xml index a790607752ed8..ee68e47fefb64 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateNewIndex.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateNewIndex.xml index f79c6e0376a7f..756f9b7d686da 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateNewIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateNewIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplatePreview.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplatePreview.xml index 0368e79b1bca2..ca7bab9273ded 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplatePreview.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplatePreview.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueue.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueue.xml index 6ad922a6febb6..dc95077086a60 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueue.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueue.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Customer.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Customer.xml new file mode 100644 index 0000000000000..481daae728279 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Customer.xml @@ -0,0 +1,24 @@ + + + + + + John + Doe + JohnDoe_%isolation%@example.com + 1 + 123123^q + 123123^q + 01/01/1990 + Male + + General + + + + diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Template.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Template.xml index a7243e44229cf..2f291ce7ccb3d 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Template.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Template.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/ActionNewsletterTemplateEntityTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/ActionNewsletterTemplateEntityTest.php index a79ea3995eeff..66c9d5c9fffd1 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/ActionNewsletterTemplateEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/ActionNewsletterTemplateEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterTemplateEntityTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterTemplateEntityTest.php index 62fb186a3c674..2ae9e5770e9a9 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterTemplateEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterTemplateEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml index 338bf69c7c60e..968d5baf807fa 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.php index 2ec44f0e30313..e5c8fde43f88e 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/PreviewNewsletterTemplateEntityTest.php @@ -1,6 +1,6 @@ + stable:no default diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateNewsletterTemplateTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateNewsletterTemplateTest.php index f6d29ba6a843b..e3f2970b86613 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateNewsletterTemplateTest.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateNewsletterTemplateTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/etc/curl/di.xml index 58c9d1479c527..aa7915034d061 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/OfflinePayments/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/OfflinePayments/Test/Repository/ConfigData.xml index 77d83ef29d311..4920441d0cdee 100644 --- a/dev/tests/functional/tests/app/Magento/OfflinePayments/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/OfflinePayments/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -229,5 +229,20 @@ 1 + + + + cataloginventory + 1 + Yes + 1 + + + cataloginventory + 1 + Yes + 1 + + diff --git a/dev/tests/functional/tests/app/Magento/OfflineShipping/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/OfflineShipping/Test/Repository/ConfigData.xml index e9461c64f4f71..d021ce7e94224 100644 --- a/dev/tests/functional/tests/app/Magento/OfflineShipping/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/OfflineShipping/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache.php index e81463a0132ee..70406963102d1 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache.php @@ -1,6 +1,6 @@ "Blocks HTML output", + 'full_page' => "Page Cache", ]; /** diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCategoryCaching.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCategoryCaching.php new file mode 100644 index 0000000000000..330baba942a04 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCategoryCaching.php @@ -0,0 +1,63 @@ +getDataFieldConfig('category_products')['source']->getProducts(); + foreach ($products as $product) { + $assertProductNotVisible->processAssert($categoryView, $cmsIndex, $product, $category); + } + + $cron->run(); + $cron->run(); + + foreach ($products as $product) { + $assertProduct->processAssert($categoryView, $cmsIndex, $product, $category); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Category products are visible after indexing.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php index 33349f3dcc0e6..c11a7ce1ec2bf 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheInvalidationTest.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheInvalidationTest.php new file mode 100644 index 0000000000000..b4003bd796b58 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheInvalidationTest.php @@ -0,0 +1,109 @@ +browser = $browser; + $this->fixtureFactory = $fixtureFactory; + $this->editProductPage = $editProductPage; + } + + /** + * Open category on the 2nd website and reassign product. + * + * @param CatalogProductSimple $product + * @param Store $store + * @return array + */ + public function test( + CatalogProductSimple $product, + Store $store + ) { + //Preconditions: + $product->persist(); + $store->persist(); + + //Steps + $category = $product->getDataFieldConfig('category_ids')['source']->getCategories()[0]; + $storeGroup = $store->getDataFieldConfig('group_id')['source']->getStoreGroup(); + $website = $storeGroup->getDataFieldConfig('website_id')['source']->getWebsite(); + $url = $_ENV['app_frontend_url'] . 'websites/' . $website->getCode() . '/' . $category->getUrlKey() . '.html'; + $this->browser->open($url); + $this->browser->open($url); + + $productFixture = $this->fixtureFactory->createByCode( + 'catalogProductSimple', + ['data' => ['website_ids' => [['store' => $store]]]] + ); + $this->editProductPage->open(['id' => $product->getId()]); + $this->editProductPage->getProductForm()->fill($productFixture); + $this->editProductPage->getFormPageActions()->save(); + + return [ + 'category' => $category, + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheInvalidationTest.xml b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheInvalidationTest.xml new file mode 100644 index 0000000000000..3333af46d1f88 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheInvalidationTest.xml @@ -0,0 +1,17 @@ + + + + + + product_with_category + custom_store + + + + + diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheStatusOnScheduledIndexingTest.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheStatusOnScheduledIndexingTest.php new file mode 100644 index 0000000000000..65be44f85dbb1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheStatusOnScheduledIndexingTest.php @@ -0,0 +1,136 @@ +indexManagement = $indexManagement; + $this->categoryEdit = $categoryEdit; + $this->browser = $browser; + $this->fixtureFactory = $fixtureFactory; + $this->cache = $cache; + } + + /** + * Create category with products and verify cache invalidation. + * + * @param Category $initialCategory + * @param Category $category + * @return array + */ + public function test(Category $initialCategory, Category $category) + { + $this->indexManagement->open(); + $this->indexManagement->getMainBlock()->massaction([], 'Update by Schedule', false, 'Select All'); + $initialCategory->persist(); + $this->cache->flush(); + + $this->browser->open($_ENV['app_frontend_url'] . $initialCategory->getUrlKey() . '.html'); + $this->categoryEdit->open(['id' => $initialCategory->getId()]); + $this->categoryEdit->getEditForm()->fill($category); + $this->categoryEdit->getFormPageActions()->save(); + + $products = $category->getDataFieldConfig('category_products')['source']->getProducts(); + return [ + 'category' => $this->fixtureFactory->createByCode( + 'category', + [ + 'data' => array_merge( + $initialCategory->getData(), + $category->getData(), + ['category_products' => ['products' => $products]] + ) + ] + ), + ]; + } + + /** + * Restore indexers mode. + * + * @return void + */ + public function tearDown() + { + $this->indexManagement->open(); + $this->indexManagement->getMainBlock()->massaction([], 'Update on Save', false, 'Select All'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheStatusOnScheduledIndexingTest.xml b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheStatusOnScheduledIndexingTest.xml new file mode 100644 index 0000000000000..696d84d6f390d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/CacheStatusOnScheduledIndexingTest.xml @@ -0,0 +1,18 @@ + + + + + + default + catalogProductSimple::default,catalogProductSimple::product_20_dollar + Enabled + + + + + diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushAdditionalCachesTest.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushAdditionalCachesTest.php index 8fd543d88a8af..2a99e9b672bac 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushAdditionalCachesTest.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushAdditionalCachesTest.php @@ -1,6 +1,6 @@ + severity:S2 Flush Catalog Images Cache The image cache was cleaned. + severity:S2 Flush JavaScript/CSS Cache The JavaScript/CSS cache has been cleaned. + severity:S2 Flush Static Files Cache The static files cache has been cleaned. diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushStaticFilesCacheButtonVisibilityTest.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushStaticFilesCacheButtonVisibilityTest.php index 28090b8662903..9efc4f41ce427 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushStaticFilesCacheButtonVisibilityTest.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/TestCase/FlushStaticFilesCacheButtonVisibilityTest.php @@ -1,6 +1,6 @@ + severity:S3 diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/PageCache/Test/etc/di.xml new file mode 100644 index 0000000000000..21aebc4f15c46 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/etc/di.xml @@ -0,0 +1,24 @@ + + + + + + S2 + + + + + S2 + + + + + S3 + + + diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.php deleted file mode 100644 index 3e8226d371ff4..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.php +++ /dev/null @@ -1,17 +0,0 @@ -getData(); - $fields = []; - foreach ($data as $name => $dataValue) { - $fields['toggle_' . $name] = 'Yes'; - $fields[$name] = $dataValue; - } - $mapping = $this->dataMapping($fields); + unset($data['payment_code']); + $mapping = $this->dataMapping($data); $this->_fill($mapping, $element); return $this; diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/PaymentCc.xml similarity index 87% rename from dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.xml rename to dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/PaymentCc.xml index e5fb6d0cf3403..a93679202eca1 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/Cc.xml +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Block/Form/PaymentCc.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php new file mode 100644 index 0000000000000..4781b3f775e4a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php @@ -0,0 +1,67 @@ +getCreateBlock()->getBillingMethodBlock() + ->getJsErrors(); + $creditCardEmpty = $creditCard->get('visa_empty'); + foreach (array_keys($creditCardEmpty) as $field) { + \PHPUnit_Framework_Assert::assertTrue( + isset($actualRequiredFields[$field]), + "Field '$field' is not highlighted with an JS error." + ); + $expected = self::REQUIRE_MESSAGE; + if (in_array($field, ['cc_number', 'cc_cid'])) { + $expected = self::VALID_NUMBER_MESSAGE; + } + \PHPUnit_Framework_Assert::assertEquals( + $expected, + $actualRequiredFields[$field], + "Field '$field' is not highlighted as required." + ); + } + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'All required fields on customer form are highlighted.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php index c1bcb2991dd1e..870a7402c399c 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php @@ -1,6 +1,6 @@ @@ -12,6 +12,8 @@ entity_type="credit_card" repository_class="Magento\Payment\Test\Repository\CreditCard" class="Magento\Payment\Test\Fixture\CreditCard"> + + diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCardAdmin.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCardAdmin.xml deleted file mode 100644 index 87e69cee86add..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Fixture/CreditCardAdmin.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml index f6c93407a0ccd..138342081fadb 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCard.xml @@ -1,7 +1,7 @@ @@ -14,6 +14,21 @@ 123 + + Visa + 4111111111111111 + 01 - January + 2020 + 123 + + + + 4012888888881881 + 02 - February + 2021 + 123 + + 378282246310005 02 - February @@ -27,5 +42,27 @@ 2020 123 + + + + + + + + + + + 4111111111111111 + 01 - January + 2020 + 306 + + + + 5555555555554444 + 01 - January + 2020 + 123 + diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml deleted file mode 100644 index 1109b70eec7cc..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Repository/CreditCardAdmin.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - Visa - 4111111111111111 - 01 - January - 2020 - 123 - - - - Visa - 4617747819866651 - 01 - January - 2020 - 123 - - - diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/TestCase/ConflictResolutionTest.php b/dev/tests/functional/tests/app/Magento/Payment/Test/TestCase/ConflictResolutionTest.php index b1c2d71a43bdd..17f54c05140b1 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/TestCase/ConflictResolutionTest.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/TestCase/ConflictResolutionTest.php @@ -1,6 +1,6 @@ @@ -40,7 +40,7 @@ - test_type:3rd_party_test + test_type:3rd_party_test, severity:S2 diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/etc/di.xml new file mode 100644 index 0000000000000..efa9fff26901e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/etc/di.xml @@ -0,0 +1,34 @@ + + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + + + S2 + + + diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/etc/fixture.xml b/dev/tests/functional/tests/app/Magento/Payment/Test/etc/fixture.xml index 4cade4a09c6e1..00c172c225a7f 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/etc/fixture.xml +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/etc/fixture.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Express/Review.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Express/Review.php index d51d5c4e39f3a..d4d230f8623cb 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Express/Review.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Express/Review.php @@ -1,6 +1,6 @@ + + + + + select + #credit_card_type + + + #credit_card_number + + + [name=expiryMonth] + + + [name=expiryYear] + + + [name=cvv2] + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PayflowLink/Cc.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PayflowLink/Cc.php new file mode 100644 index 0000000000000..73bf9c0ad33d2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PayflowLink/Cc.php @@ -0,0 +1,17 @@ + + + + + + #cc_number + + + #expdate_month + + + #expdate_year + + + #cvv2_number + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PaymentsAdvanced/Cc.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PaymentsAdvanced/Cc.php new file mode 100644 index 0000000000000..8cb68b8b4eb38 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Form/PaymentsAdvanced/Cc.php @@ -0,0 +1,17 @@ + + + + + + #cc_number + + + #expdate_month + + + #expdate_year + + + #cvv2_number + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Onepage/Payment/HostedPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Onepage/Payment/HostedPro.php new file mode 100644 index 0000000000000..c76e8655ce32a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Onepage/Payment/HostedPro.php @@ -0,0 +1,20 @@ +switchToPaypalFrame(); + $formBlock = $this->blockFactory->create( + $this->formBlockCc, + ['element' => $this->_rootElement->find($this->creditCardForm)] + ); + $formBlock->fill($creditCard, $iframeRootElement); + $iframeRootElement->find($this->payNowButton)->click(); + $this->browser->switchToFrame(); + } + + /** + * Check if error message is appeared. + * + * @return bool + */ + public function isErrorMessageVisible() + { + $isErrorMessageVisible = false; + if ($this->_rootElement->find($this->paypalIframe)->isPresent()) { + $iframeRootElement = $this->switchToPaypalFrame(); + $isErrorMessageVisible = $iframeRootElement->find($this->errorMessage)->isVisible(); + $this->browser->switchToFrame(); + } + return $isErrorMessageVisible; + } + + /** + * Change the focus to a PayPal frame. + * + * @return ElementInterface + */ + private function switchToPaypalFrame() + { + $iframeLocator = $this->browser->find($this->paypalIframe)->getLocator(); + $this->browser->switchToFrame($iframeLocator); + return $this->browser->find('body'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressLogin.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressLogin.php index 65b38b19320d9..13f08947a2182 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressLogin.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressLogin.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressMainLogin.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressMainLogin.php index 936e9a084c54d..e378320c167b9 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressMainLogin.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressMainLogin.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressOldReview.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressOldReview.php index 5bb5cfa67ab9d..17f595c6743f3 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressOldReview.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/ExpressOldReview.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupCreate.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupCreate.php index 217e691205a6f..3db98755513e4 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupCreate.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupCreate.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupPersonalAccount.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupPersonalAccount.php index c7ca52ef65068..f7b85aba0f0d6 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupPersonalAccount.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/Sandbox/SignupPersonalAccount.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php index d83ae0c53ec0a..82f68a0a85988 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/ExpressCheckout.php @@ -1,6 +1,6 @@ '#payment_us_paypal_alternative_payment_methods_express_' . - 'checkout_us_express_checkout_required_express_checkout_required_express_checkout_business_account', 'API Username' => '#payment_us_paypal_alternative_payment_methods_express_checkout_us_express_checkout_' . 'required_express_checkout_required_express_checkout_api_username', 'API Password' => '#payment_us_paypal_alternative_payment_methods_express_checkout_us_express_checkout_' . @@ -72,8 +70,6 @@ public function getFields() */ public function specifyCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account']) - ->setValue('test@test.com'); $this->_rootElement->find($this->fields['API Username'])->setValue('1'); $this->_rootElement->find($this->fields['API Password'])->setValue('1'); $this->_rootElement->find($this->fields['API Signature'])->setValue('1'); @@ -86,7 +82,6 @@ public function specifyCredentials() */ public function clearCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue(''); $this->_rootElement->find($this->fields['API Username'])->setValue(''); $this->_rootElement->find($this->fields['API Password'])->setValue(''); $this->_rootElement->find($this->fields['API Signature'])->setValue(''); diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php index de6eb107c61ce..de0f117bf3163 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowLink.php @@ -1,6 +1,6 @@ '#payment_us_paypal_payment_gateways_payflow_link_us_' . - 'payflow_link_required_payflow_link_payflow_link_business_account', 'Partner' => '#payment_us_paypal_payment_gateways_payflow_link_us_payflow_link_required_payflow_link_payflow_' . 'link_partner', 'Vendor' => '#payment_us_paypal_payment_gateways_payflow_link_us_payflow_link_required_payflow_link_payflow_' . @@ -60,8 +58,6 @@ class PayflowLink extends Block */ public function specifyCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account']) - ->setValue('test@test.com'); $this->_rootElement->find($this->fields['Partner'])->setValue('1'); $this->_rootElement->find($this->fields['Vendor'])->setValue('1'); $this->_rootElement->find($this->fields['User'])->setValue('1'); @@ -75,7 +71,6 @@ public function specifyCredentials() */ public function clearCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue(''); $this->_rootElement->find($this->fields['Partner'])->setValue(''); $this->_rootElement->find($this->fields['Vendor'])->setValue(''); $this->_rootElement->find($this->fields['User'])->setValue(''); diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php index f05092745c760..cc5c9337ebe5a 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PayflowPro.php @@ -1,6 +1,6 @@ '#payment_us_paypal_payment_gateways_paypal_payflowpro_' . - 'with_express_checkout_paypal_payflow_required_paypal_payflow_api_settings_business_account', 'Partner' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_payflow_' . 'required_paypal_payflow_api_settings_partner', 'Vendor' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_payflow_' . @@ -42,7 +40,7 @@ class PayflowPro extends Block '_payflow_required_enable_paypal_payflow', 'Enable PayPal Credit' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal' . '_payflow_required_enable_express_checkout_bml_payflow', - 'Vault enabled' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_' . + 'Vault Enabled' => '#payment_us_paypal_payment_gateways_paypal_payflowpro_with_express_checkout_paypal_' . 'payflow_required_payflowpro_cc_vault_active' ]; @@ -60,8 +58,6 @@ class PayflowPro extends Block */ public function specifyCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account']) - ->setValue('test@test.com'); $this->_rootElement->find($this->fields['Partner'])->setValue('1'); $this->_rootElement->find($this->fields['Vendor'])->setValue('1'); $this->_rootElement->find($this->fields['User'])->setValue('1'); @@ -75,7 +71,6 @@ public function specifyCredentials() */ public function clearCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue(''); $this->_rootElement->find($this->fields['Partner'])->setValue(''); $this->_rootElement->find($this->fields['Vendor'])->setValue(''); $this->_rootElement->find($this->fields['User'])->setValue(''); diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php index cd6d1a5b1b38a..fef7c3a2bf39a 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsAdvanced.php @@ -1,6 +1,6 @@ '#payment_us_paypal_group_all_in_one_payflow_advanced_' . - 'required_settings_payments_advanced_business_account', 'Partner' => '#payment_us_paypal_group_all_in_one_payflow_advanced_required_settings_payments_advanced_partner', 'Vendor' => '#payment_us_paypal_group_all_in_one_payflow_advanced_required_settings_payments_advanced_vendor', 'User' => '#payment_us_paypal_group_all_in_one_payflow_advanced_required_settings_payments_advanced_user', @@ -54,8 +52,6 @@ class PaymentsAdvanced extends Block */ public function specifyCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account']) - ->setValue('test@test.com'); $this->_rootElement->find($this->fields['Partner'])->setValue('1'); $this->_rootElement->find($this->fields['Vendor'])->setValue('1'); $this->_rootElement->find($this->fields['User'])->setValue('1'); @@ -69,7 +65,6 @@ public function specifyCredentials() */ public function clearCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue(''); $this->_rootElement->find($this->fields['Partner'])->setValue(''); $this->_rootElement->find($this->fields['Vendor'])->setValue(''); $this->_rootElement->find($this->fields['User'])->setValue(''); diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php index 709dc4b54b53f..f8ccbd48e909d 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Block/System/Config/PaymentsPro.php @@ -1,6 +1,6 @@ '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_' . - 'payflow_required_paypal_payflow_api_settings_business_account', 'Partner' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_paypal_payflow_api_' . 'settings_partner', 'Vendor' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_paypal_payflow_api_' . @@ -42,7 +40,7 @@ class PaymentsPro extends Block '_payflow', 'Enable PayPal Credit' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_enable_' . 'express_checkout_bml_payflow', - 'Vault enabled' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_payflowpro_cc_vault' . + 'Vault Enabled' => '#payment_us_paypal_group_all_in_one_wpp_usuk_paypal_payflow_required_payflowpro_cc_vault' . '_active' ]; @@ -60,8 +58,6 @@ class PaymentsPro extends Block */ public function specifyCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account']) - ->setValue('test@test.com'); $this->_rootElement->find($this->fields['Partner'])->setValue('1'); $this->_rootElement->find($this->fields['Vendor'])->setValue('1'); $this->_rootElement->find($this->fields['User'])->setValue('1'); @@ -75,7 +71,6 @@ public function specifyCredentials() */ public function clearCredentials() { - $this->_rootElement->find($this->fields['Email Associated with PayPal Merchant Account'])->setValue(''); $this->_rootElement->find($this->fields['Partner'])->setValue(''); $this->_rootElement->find($this->fields['Vendor'])->setValue(''); $this->_rootElement->find($this->fields['User'])->setValue(''); diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php index 9d2cbe0f38e0d..e60c5ff85bc6c 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml index c2461cf39ae6c..f96b4efbc5ecd 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Adminhtml/SystemConfigEditSectionPayment.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/CheckoutOnepage.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/CheckoutOnepage.xml new file mode 100644 index 0000000000000..9840f41c6e48f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/CheckoutOnepage.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/OrderReviewExpress.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/OrderReviewExpress.xml index 66071374c66eb..60ef7dd65e9d2 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/OrderReviewExpress.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/OrderReviewExpress.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/AccountSignup.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/AccountSignup.xml index fad07b0df1e56..ce48b9f11e2e3 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/AccountSignup.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/AccountSignup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/ExpressReview.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/ExpressReview.xml index 5f872f28c2305..9bd92b248e05c 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/ExpressReview.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/ExpressReview.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupAddCard.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupAddCard.xml index 55737bc0d7d42..6e82123c2912f 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupAddCard.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupAddCard.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupCreate.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupCreate.xml index f8af1598215b6..5b9a2208bad92 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupCreate.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Page/Sandbox/SignupCreate.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml index 0706f45beeb4b..51f18cd929a97 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/ConfigData.xml @@ -1,95 +1,183 @@ + + + payment + 1 + United Kingdom + GB + + + + + payment + 1 + United States + US + + + - + payment 1 - Yes - PAYPAL_BUSINESS_ACCOUNT + Email Associated with PayPal Merchant Account (Optional) + %payflow_pro_business_account% - + payment 1 - - PAYPAL_API_USERNAME + Partner + %payflow_pro_partner% - + payment 1 - - PAYPAL_API_PASSWORD + User + %payflow_pro_user% + + + payment + 1 + Vendor + %payflow_pro_vendor% + + + payment + 1 + Password + %payflow_pro_pwd% + + + payment + 1 + Test Mode + 1 + + + payment + 1 + Enable this Solution + 1 + + + + + payment + 1 + Enable this Solution + 0 - + + + + + payment + 1 + Email Associated with PayPal Merchant Account (Optional) + %payflow_pro_business_account% + + + payment + 1 + Partner + %payflow_pro_partner% + + + payment + 1 + User + %payflow_pro_user% + + + payment + 1 + Password + %payflow_pro_pwd% + + + payment + 1 + Vendor + %payflow_pro_vendor% + + payment 1 - PAYPAL_API_SIGNATURE + 1 - + payment 1 Yes 1 - + payment 1 Yes 1 - + payment 1 Yes 1 - - - + payment 1 Yes + 1 + + + + + payment + 1 + No 0 - + payment 1 - Yes - PAYPAL_BUSINESS_ACCOUNT + Email Associated with PayPal Merchant Account (Optional) + %payflow_pro_fraud_protection_enabled_business_account% payment 1 - - PAYMENT_PAYFLOWPRO_PARTNER + Partner + %payflow_pro_fraud_protection_enabled_partner% payment 1 - - PAYMENT_PAYFLOWPRO_USER + User + %payflow_pro_fraud_protection_enabled_user% payment 1 - - PAYMENT_PAYFLOWPRO_PWD + Password + %payflow_pro_fraud_protection_enabled_pwd% payment 1 - - PAYMENT_PAYFLOWPRO_VENDOR + Vendor + %payflow_pro_fraud_protection_enabled_vendor% payment @@ -122,11 +210,90 @@ 1 - + + payment + 1 + No + 0 + + + + + + payment + 1 + Yes + 1 + + + + + payment + 1 + No + 0 + + + + + + payment + 1 + Yes + 1 + + + + + + payment + 1 + Yes + HOSTED_PRO_BUSINESS_ACCOUNT + + + payment + 1 + + HOSTED_PRO_API_USERNAME + + + payment + 1 + + HOSTED_PRO_API_PASSWORD + + + payment + 1 + + HOSTED_PRO_API_SIGNATURE + + + payment + 1 + Yes + 1 + + + payment + 1 + Yes + 1 + + payment 1 Yes + 1 + + + + + payment + 1 + No 0 @@ -184,41 +351,100 @@ + + + payment + 1 + Email Associated with PayPal Merchant Account + %payflow_link_business_account_email% + + + payment + 1 + Partner + %payflow_link_partner% + + + payment + 1 + User + %payflow_link_user% + + + payment + 1 + Password + %payflow_link_password% + + + payment + 1 + Vendor + %payflow_link_vendor% + + + payment + 1 + Yes + 1 + + + payment + 1 + Yes + 1 + + + + + payment + 1 + No + 0 + + + payment 1 - Yes - PAYPAL_BUSINESS_ACCOUNT + Email Associated with PayPal Merchant Account + %payflow_link_business_account_email% payment 1 - - PAYMENT_PAYFLOWLINK_PARTNER + Partner + %payflow_link_partner% payment 1 - - PAYMENT_PAYFLOWLINK_USER + User + %payflow_link_user% payment 1 - - PAYMENT_PAYFLOWLINK_PWD + Password + %payflow_link_password% payment 1 - - PAYMENT_PAYFLOWLINK_VENDOR + Vendor + %payflow_link_vendor% payment 1 - + Yes + 1 + + + payment + 1 + Yes 1 @@ -250,7 +476,7 @@ payment 1 - Yes + No 0 @@ -277,6 +503,7 @@ 0 + payment @@ -293,5 +520,34 @@ 0 + + + + payment + 1 + Yes + 1 + + + payment + 1 + No + 0 + + + + + payment + 1 + No + 0 + + + payment + 1 + Yes + 1 + + diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/CreditCard.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/CreditCard.xml similarity index 53% rename from dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/CreditCard.xml rename to dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/CreditCard.xml index c6b8eab58205e..b2d27be1cebcb 100644 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Repository/CreditCard.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/CreditCard.xml @@ -1,15 +1,16 @@ - - - 4111111111111111 - 01 - January + + + V + 4032034402702800 + 01 2020 123 diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/SandboxCustomer.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/SandboxCustomer.xml index 7443516c3a70f..48a7cd435a0e4 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/SandboxCustomer.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Repository/SandboxCustomer.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseOrderTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseOrderTest.xml new file mode 100644 index 0000000000000..9aa98909f7442 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseOrderTest.xml @@ -0,0 +1,57 @@ + + + + + + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflowpro + + 15.00 + + + 15.00 + + visa_default + Complete + paypal_direct + test_type:3rd_party_test, severity:S0 + + + + + + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflowpro + full_invoice_with_product_10_dollar + + 15.00 + + + 15.00 + + visa_default + Complete + payflowpro, payflowpro_use_vault + test_type:3rd_party_test, severity:S0 + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.php new file mode 100644 index 0000000000000..146f0e2c2ff7b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.php @@ -0,0 +1,44 @@ + Orders page. + * 3. Open order. + * 4. Click 'Ship' button and submit shipment. + * 5. Click 'Invoice' button. + * 6. Select Amount=Capture Online. + * 7. Click 'Submit Invoice' button. + * 11. Perform assertions. + * + * @group Paypal + * @ZephyrId MAGETWO-13016 + */ +class CloseSalesWithHostedProTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + /* end tags */ + + /** + * Complete order paid PayPal Payments Pro Hosted Solution. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.xml new file mode 100644 index 0000000000000..083af5ac3a338 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CloseSalesWithHostedProTest.xml @@ -0,0 +1,38 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + hosted_pro + + 145.98 + + + 145.98 + + credit_card_hostedpro + visa_hosted_pro + false + Complete + merchant_country_gb, hosted_pro, config_base_currency_gb + test_type:3rd_party_test, severity:S0 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateOnlineCreditMemoTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateOnlineCreditMemoTest.xml new file mode 100644 index 0000000000000..419ccb61a7f79 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateOnlineCreditMemoTest.xml @@ -0,0 +1,89 @@ + + + + + + test_type:3rd_party_test, severity:S0 + catalogProductSimple::product_10_dollar + default + guest + + + 0 + + + + + 15.00 + + + US_address_1_without_email + Flat Rate + Fixed + payflowpro + paypal_direct + visa_default + - + Yes + Closed + + Refund + Yes + + + Capture + Yes + + + + + + + + + test_type:3rd_party_test, severity:S0 + catalogProductSimple::product_10_dollar + default + guest + + + 0 + + + + + 15.00 + + + US_address_1_without_email + Flat Rate + Fixed + payflowpro + payflowpro + visa_default + Closed + + Authorization + Yes + + + Refund + Yes + + + Capture + Yes + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.php new file mode 100644 index 0000000000000..d0c46c7a8492d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.php @@ -0,0 +1,50 @@ + Orders. + * 3. Click Create New Order. + * 4. Select Customer created in preconditions. + * 5. Add Product. + * 6. Fill data according dataset. + * 7. Click Update Product qty. + * 8. Fill data according dataset. + * 9. Click Get Shipping Method and rates. + * 10. Fill data according dataset. + * 11. Select payment method Credit Card (PayFlow Pro) + * 12. Leave empty required fields for credit card + * 13. Click Submit order button + * + * @group PayPal + * @ZephyrId MAGETWO-58934 + */ +class CreatePayFlowOrderBackendNegativeTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + const SEVERITY = 'S2'; + /* end tags */ + + /** + * Runs sales order on backend. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml new file mode 100644 index 0000000000000..f220e2c01d733 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreatePayFlowOrderBackendNegativeTest.xml @@ -0,0 +1,28 @@ + + + + + + test_type:3rd_party_test, severity:S2 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + No + Flat Rate + Fixed + + 15.00 + + payflowpro + visa_empty + Yes + payflowpro, payflowpro_use_vault + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml index 64a191040b8a4..1cbad7424d76f 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateVaultOrderBackendTest.xml @@ -1,14 +1,14 @@ - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 catalogProductSimple::product_10_dollar default US_address_1_without_email @@ -19,8 +19,8 @@ 15.00 payflowpro - credit_card_admin - visa_default + payflowpro_cc_vault + visa_default_admin Yes payflowpro, payflowpro_use_vault Processing diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromProductPageTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromProductPageTest.php index c8fb3e4f30f19..897cc09bfbf57 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromProductPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromProductPageTest.php @@ -1,6 +1,6 @@ @@ -27,7 +27,7 @@ paypal_express paypal_express, freeshipping - test_type:3rd_party_test + test_type:3rd_party_test_deprecated, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromShoppingCartTest.php index 7fc35ff1eb6fd..6450c2c812f6d 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromShoppingCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutFromShoppingCartTest.php @@ -1,6 +1,6 @@ @@ -28,7 +28,7 @@ 145.98 payflowpro - test_type:3rd_party_test + test_type:3rd_party_test_deprecated, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutOnePageTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutOnePageTest.php index b40adf986dbe9..029b666c22beb 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutOnePageTest.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ExpressCheckoutOnePageTest.php @@ -1,6 +1,6 @@ @@ -26,7 +26,7 @@ paypal_express paypal_express - test_type:3rd_party_test + test_type:3rd_party_test_deprecated, severity:S0 @@ -51,7 +51,7 @@ paypal_express payflowlink - test_type:3rd_party_test + test_type:3rd_party_test_deprecated, severity:S0 @@ -76,7 +76,7 @@ paypal_express paypal_express - test_type:3rd_party_test + test_type:3rd_party_test_deprecated diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressCheckoutFromShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressCheckoutFromShoppingCartTest.php index 07f03b1c931cf..1708ece5706cb 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressCheckoutFromShoppingCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressCheckoutFromShoppingCartTest.php @@ -1,6 +1,6 @@ @@ -10,7 +10,7 @@ catalogProductSimple::product_10_dollar paypal_express, paypal_express_in_context - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressOnePageCheckoutTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressOnePageCheckoutTest.php index ff06e6b10266e..a172e6e5a2f7d 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressOnePageCheckoutTest.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/InContextExpressOnePageCheckoutTest.php @@ -1,6 +1,6 @@ @@ -18,7 +18,7 @@ paypal_express paypal_express_in_context, paypal_express, freeshipping - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/NavigateMenuTest.xml new file mode 100644 index 0000000000000..0cd056eaf710c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/NavigateMenuTest.xml @@ -0,0 +1,23 @@ + + + + + + severity:S0 + Reports > PayPal Settlement + PayPal Settlement Reports + + + + severity:S0 + Sales > Billing Agreements + Billing Agreements + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutDeclinedTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutDeclinedTest.xml new file mode 100644 index 0000000000000..e4c0f0196beeb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutDeclinedTest.xml @@ -0,0 +1,53 @@ + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + AVS_street_does_not_match_address + guest + Flat Rate + Fixed + payflowpro + visa_default + payflowpro, payflowpro_avs_street_does_not_match + An error occurred on the server. Please try to place the order again. + + + + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflowpro + visa_default + An error occurred on the server. Please try to place the order again. + payflowpro, payflowpro_use_avs_zip + test_type:3rd_party_test, severity:S1 + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflowpro + visa_cvv_mismatch + payflowpro, payflowpro_avs_security_code_does_not_match + An error occurred on the server. Please try to place the order again. + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.php new file mode 100644 index 0000000000000..4dda2d7ae5d68 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.php @@ -0,0 +1,51 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.xml new file mode 100644 index 0000000000000..f78049ad024ce --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutHostedProTest.xml @@ -0,0 +1,35 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + hosted_pro + + 145.98 + + credit_card_hostedpro + visa_hosted_pro + false + merchant_country_gb, hosted_pro, config_base_currency_gb + Processing + test_type:3rd_party_test, severity:S0 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.php new file mode 100644 index 0000000000000..1af1b34cc3d70 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.php @@ -0,0 +1,51 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.xml new file mode 100644 index 0000000000000..259a918c99d50 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPayflowLinkTest.xml @@ -0,0 +1,34 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflow_link + + 145.98 + + visa_default + false + payflowlink + Processing + test_type:3rd_party_test, severity:S0 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.php new file mode 100644 index 0000000000000..1fdaba086866f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.php @@ -0,0 +1,51 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.xml new file mode 100644 index 0000000000000..530623ef97bff --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutPaymentsAdvancedTest.xml @@ -0,0 +1,34 @@ + + + + + + catalogProductSimple::product_10_dollar + configurableProduct::with_one_option + bundleProduct::bundle_fixed_100_dollar_product + us_ca_ny_rule + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflow_advanced + + 145.98 + + visa_default + false + payments_advanced + Processing + test_type:3rd_party_test, severity:S0 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutTest.xml new file mode 100644 index 0000000000000..0229ba550aa01 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/OnePageCheckoutTest.xml @@ -0,0 +1,144 @@ + + + + + + catalogProductSimple::product_10_dollar + default + US_address_1 + us_ca_ny_rule + guest + Flat Rate + Fixed + payflowpro + + 15.83 + + visa_default + false + payflowpro + test_type:3rd_party_test, severity:S1 + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + UK_address_without_email + guest + Flat Rate + Fixed + payflowpro + + 15.00 + + credit_card + visa_default + false + payflowpro_fraud_filters_enabled + + Under review by Fraud Service + #N: No Details matched + + Processing + + + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + AVS_street_match_address + guest + Flat Rate + Fixed + payflowpro + + 15.00 + + credit_card + visa_default + false + payflowpro_fraud_filters_enabled + + #Y: Yes. Matched Address and five-didgit ZIP + + Processing + + + + + + + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflowpro + + 15.00 + + visa_default + paypal_direct + test_type:3rd_party_test, severity:S1 + + + + + + + catalogProductSimple::product_10_dollar + default + AVS_zip_match_address + guest + Flat Rate + Fixed + payflowpro + visa_default + + #Y: Yes. Matched Address and five-didgit ZIP + + payflowpro, payflowpro_use_avs_zip + Processing + test_type:3rd_party_test, severity:S1 + + + + + + test_type:3rd_party_test, severity:S1 + catalogProductSimple::product_10_dollar + default + US_address_1_without_email + guest + Flat Rate + Fixed + payflowpro + + 15.00 + + visa_default + payflowpro, payflowpro_avs_security_code_does_not_match + + #Y: Matched (CVV2CSC) + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml index bc3ee3cef1c68..f502eeec23198 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/ReorderUsingVaultTest.xml @@ -1,13 +1,13 @@ - + Reorder from Admin with saved within PayPal Payflow Pro credit card for Guest Customer catalogProductSimple::product_10_dollar default @@ -19,11 +19,11 @@ 15.00 payflowpro - credit_card + payflowpro_cc_vault visa_default payflowpro, payflowpro_use_vault Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml index a71dd812b50f7..f2fc6e54ad46f 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/UseVaultOnCheckoutTest.xml @@ -1,7 +1,7 @@ @@ -15,12 +15,12 @@ Flat Rate Fixed payflowpro - credit_card + payflowpro_cc_vault visa_default Yes payflowpro, payflowpro_use_vault Processing - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 Processing Back, Cancel, Send Email, Hold, Invoice, Ship, Reorder, Edit diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckExpressConfigStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckExpressConfigStep.php index 2a0d87edcca7e..ef1a76078c0fc 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckExpressConfigStep.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckExpressConfigStep.php @@ -1,6 +1,6 @@ payflowProConfigBlock->enablePayflowPro(); $this->assertFieldsAreActive->processAssert( $this->systemConfigEditSectionPayment, - [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault enabled']] + [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault Enabled']] ); $this->assertFieldsAreEnabled->processAssert( $this->systemConfigEditSectionPayment, diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsAdvancedConfigStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsAdvancedConfigStep.php index 0cfa76efd7bbf..1982bc5f30b81 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsAdvancedConfigStep.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckPaymentsAdvancedConfigStep.php @@ -1,6 +1,6 @@ paymentsProConfigBlock->enablePaymentsPro(); $this->assertFieldsAreActive->processAssert( $this->systemConfigEditSectionPayment, - [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault enabled']] + [$enablers['Enable this Solution'], $enablers['Enable PayPal Credit'], $enablers['Vault Enabled']] ); $this->assertFieldsAreEnabled->processAssert( $this->systemConfigEditSectionPayment, diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckoutWithPaypalFromProductPageStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckoutWithPaypalFromProductPageStep.php index ba17b4c9084a4..e285408daac0c 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckoutWithPaypalFromProductPageStep.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/CheckoutWithPaypalFromProductPageStep.php @@ -1,6 +1,6 @@ checkoutOnepageSuccess = $checkoutOnepageSuccess; - } - - /** - * Get success placed order id. - * - * @return array - */ - public function run() - { - return [ - 'orderId' => $this->checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(), - ]; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/InContextCheckoutWithPaypalFromShoppingCartStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/InContextCheckoutWithPaypalFromShoppingCartStep.php index f612d6f0ff0d1..f8768b319a464 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/InContextCheckoutWithPaypalFromShoppingCartStep.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/InContextCheckoutWithPaypalFromShoppingCartStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; + $this->fixtureFactory = $fixtureFactory; + $this->creditCard = $creditCard; + $this->payment = $payment; + $this->products = $products; + } + + /** + * Place order with Hosted Pro. + * + * @return array + */ + public function run() + { + $attempts = 1; + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment); + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $this->checkoutOnepage->getHostedProBlock()->fillPaymentData($this->creditCard); + // As Paypal Sandbox is not stable there are three attempts given to place order + while ($this->checkoutOnepage->getHostedProBlock()->isErrorMessageVisible() && $attempts <= 3) { + $this->checkoutOnepage->getHostedProBlock()->fillPaymentData($this->creditCard); + $attempts++; + } + /** @var OrderInjectable $order */ + $order = $this->fixtureFactory->createByCode( + 'orderInjectable', + [ + 'data' => [ + 'entity_id' => ['products' => $this->products] + ] + ] + ); + return ['order' => $order]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPayflowLinkStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPayflowLinkStep.php new file mode 100644 index 0000000000000..d3733e5c0fe69 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPayflowLinkStep.php @@ -0,0 +1,98 @@ +checkoutOnepage = $checkoutOnepage; + $this->fixtureFactory = $fixtureFactory; + $this->creditCard = $creditCard; + $this->payment = $payment; + $this->products = $products; + } + + /** + * Place order with Payflow Link. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment); + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $this->checkoutOnepage->getPayflowLinkBlock()->fillPaymentData($this->creditCard); + + /** @var OrderInjectable $order */ + $order = $this->fixtureFactory->createByCode( + 'orderInjectable', + [ + 'data' => [ + 'entity_id' => ['products' => $this->products] + ] + ] + ); + return ['order' => $order]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPaymentsAdvancedStep.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPaymentsAdvancedStep.php new file mode 100644 index 0000000000000..051ae181e40a4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestStep/PlaceOrderWithPaymentsAdvancedStep.php @@ -0,0 +1,98 @@ +checkoutOnepage = $checkoutOnepage; + $this->fixtureFactory = $fixtureFactory; + $this->creditCard = $creditCard; + $this->payment = $payment; + $this->products = $products; + } + + /** + * Place order with Payments Advanced. + * + * @return array + */ + public function run() + { + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment); + $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->clickPlaceOrder(); + $this->checkoutOnepage->getPaymentsAdvancedBlock()->fillPaymentData($this->creditCard); + + /** @var OrderInjectable $order */ + $order = $this->fixtureFactory->createByCode( + 'orderInjectable', + [ + 'data' => [ + 'entity_id' => ['products' => $this->products] + ] + ] + ); + return ['order' => $order]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/di.xml new file mode 100644 index 0000000000000..689804f25660e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + S1 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml index f361530def861..0f96f06a91b86 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/etc/testcase.xml @@ -1,7 +1,7 @@ @@ -13,7 +13,7 @@ - + @@ -59,7 +59,7 @@ - + @@ -69,4 +69,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php b/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php new file mode 100644 index 0000000000000..0608f2d12eb5b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php @@ -0,0 +1,42 @@ +open(); + \PHPUnit_Framework_Assert::assertTrue( + !$checkoutOnepage->getMessagesBlock()->isVisible() + && $checkoutOnepage->getShippingMethodBlock()->isVisible(), + 'Checkout first step is not available.' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Checkout first step is available.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Persistent/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Persistent/Test/Repository/ConfigData.xml new file mode 100644 index 0000000000000..570b6ef7755aa --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/Repository/ConfigData.xml @@ -0,0 +1,40 @@ + + + + + + + persistent + 1 + Yes + 1 + + + persistent + 1 + No + 0 + + + + + + persistent + 1 + No + 0 + + + persistent + 1 + Yes + 1 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.php new file mode 100644 index 0000000000000..cff7e0af34af7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.php @@ -0,0 +1,181 @@ +customerAccountCreate = $customerAccountCreate; + $this->cmsIndex = $cmsIndex; + $this->logoutCustomerOnFrontendStep = $logoutCustomerOnFrontendStep; + $this->browser = $browser; + $this->catalogProductView = $catalogProductView; + $this->checkoutCart = $checkoutCart; + $this->stepFactory = $stepFactory; + } + + /** + * Prepare data. + * + * @param CatalogProductSimple $product + * @return array + */ + public function __prepare(CatalogProductSimple $product) + { + $product->persist(); + + return ['product' => $product]; + } + + /** + * Create Customer account on Storefront. + * + * @param string $configData + * @param CatalogProductSimple $product + * @param Customer $customer + * @return void + */ + public function test($configData, CatalogProductSimple $product, Customer $customer) + { + $this->configData = $configData; + $this->stepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); + + // Steps + $this->cmsIndex->open(); + $this->cmsIndex->getLinksBlock()->openLink('Create an Account'); + $this->customerAccountCreate->getRegisterForm()->registerCustomer($customer); + + // Ensure that shopping cart is empty + $this->checkoutCart->open()->getCartBlock()->clearShoppingCart(); + + $this->browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); + $this->catalogProductView->getViewBlock()->addToCart($product); + $this->catalogProductView->getMessagesBlock()->waitSuccessMessage(); + $this->logoutCustomerOnFrontendStep->run(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->stepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.xml new file mode 100644 index 0000000000000..961a6bd1ede69 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/TestCase/CheckoutWithPersistentShoppingCartTest.xml @@ -0,0 +1,17 @@ + + + + + + MAGETWO-59976: Customer can't open Product on Storefront if Persistent Cart is enabled + register_customer + clearpersistence_on_signout + + + + diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/Images/VideoDialog.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/Images/VideoDialog.php index dbed9445d1f42..04dacb21f2c0b 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/Images/VideoDialog.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/Images/VideoDialog.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/ImagesAndVideos.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/ImagesAndVideos.php index a935569682bf4..8bb08183b18e2 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/ImagesAndVideos.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Block/Adminhtml/Product/Edit/Tab/ImagesAndVideos.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php index fd34bcbc5c8a1..5008bde310bf1 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Fixture/Product/MediaGallery.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Fixture/Product/MediaGallery.php index 05bdc0e626b75..3a8ce1750794e 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Fixture/Product/MediaGallery.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Fixture/Product/MediaGallery.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/ConfigData.xml index 59bd1ceb69d20..27204bab83f2d 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/AddProductVideoTest.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/AddProductVideoTest.php index c5175df4ad078..38aaeba13ec0b 100644 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/AddProductVideoTest.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/AddProductVideoTest.php @@ -1,6 +1,6 @@ + stable:no product_with_video_youtube youtube_api_key,play_if_base @@ -15,6 +16,7 @@ + stable:no product_with_video_vimeo play_if_base diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/DeleteProductVideoTest.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/DeleteProductVideoTest.php index ebc5e0ccf93b4..1808d24859129 100644 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/DeleteProductVideoTest.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/DeleteProductVideoTest.php @@ -1,6 +1,6 @@ + stable:no product_with_video_youtube youtube_api_key,play_if_base @@ -15,6 +16,7 @@ + stable:no product_with_video_vimeo play_if_base diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.php index 30df076817dff..0e457fc6a5488 100644 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/TestCase/UpdateProductVideoTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/AbstractFilter.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/AbstractFilter.php index 00730bcb3802a..5e242514b776e 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/AbstractFilter.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/AbstractFilter.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Counts/Grid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Counts/Grid.php index 6a5e9a30aa946..9bbec18911671 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Counts/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Counts/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Totals/Grid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Totals/Grid.php index a4e329a85454a..5d387f5d42cef 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Totals/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Customer/Totals/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Product/Viewed/ProductGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Product/Viewed/ProductGrid.php index 7f91821cb4d13..01c0a25dbdd52 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Product/Viewed/ProductGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Product/Viewed/ProductGrid.php @@ -1,6 +1,6 @@ _rootElement->getElements($this->rowItem); + foreach ($rows as $row) { + $rowData = []; + foreach ($columns as $columnName) { + $rowData[$columnName] = trim($row->find('.col-' . $columnName)->getText()); + } + + $data[] = $rowData; + } + + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Customer/Grid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Customer/Grid.php index 1f99a47d87ea1..1d6187d57cdda 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Customer/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Customer/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Products/Viewed/ProductGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Products/Viewed/ProductGrid.php index 4dd8ba213c5bc..47ab14ab94739 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Products/Viewed/ProductGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Review/Products/Viewed/ProductGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/Coupons/Grid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/Coupons/Grid.php index 907831c79d79d..1df4d3dd6060f 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/Coupons/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/Coupons/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/TaxRule/Grid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/TaxRule/Grid.php index 7cdc0df478eb1..c1481e5eb1add 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/TaxRule/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Block/Adminhtml/Sales/TaxRule/Grid.php @@ -1,6 +1,6 @@ salesShippingReport = $salesShippingReport; + } + + /** + * Search in invoice report grid. + * + * @param array $shippingReport + * @return void + */ + protected function searchInShippingReportGrid(array $shippingReport) + { + $this->salesShippingReport->open(); + $this->salesShippingReport->getMessagesBlock()->clickLinkInMessage('notice', 'here'); + $this->salesShippingReport->getFilterForm()->viewsReport($shippingReport); + $this->salesShippingReport->getActionBlock()->showReport(); + } + + /** + * Prepare expected and initial results. + * + * @param array $expectedShippingData + * @param array $shipmentResult + * @return array + */ + protected function prepareExpectedResult(array $expectedShippingData, array $shipmentResult) + { + $totalShipping = $this->order->getPrice()[0]['grand_shipment_total']; + $expectedShippingData['qty'] += 1; + $expectedShippingData['total-sales-shipping'] += $totalShipping; + + $preparedResult = [$expectedShippingData, $shipmentResult]; + foreach ($preparedResult as &$result) { + $result = array_map(function ($rowData) { + return (int)$rowData; + }, $result); + } + return $preparedResult; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php index ccfac978b8e16..a31f996c6c480 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php @@ -1,6 +1,6 @@ getMessagesBlock()->getSuccessMessage(); + \PHPUnit_Framework_Assert::assertEquals( + self::LIFETIME_STATISTICS_UPDATED_MESSAGE, + $successMessage, + 'Wrong success message is displayed.' + . "\nExpected: " . self::LIFETIME_STATISTICS_UPDATED_MESSAGE + . "\nActual: " . $successMessage + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Correct message is displayed after refreshing lifetime statistics."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php index 7ef1a522a1788..e0f5b43757875 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php @@ -1,6 +1,6 @@ getMessagesBlock()->getSuccessMessage(); + \PHPUnit_Framework_Assert::assertEquals( + self::RECENT_STATISTICS_UPDATED_MESSAGE, + $successMessage, + 'Wrong success message is displayed.' + . "\nExpected: " . self::RECENT_STATISTICS_UPDATED_MESSAGE + . "\nActual: " . $successMessage + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Correct message is displayed after refreshing recent statistics."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php index 14c120281eed8..3ffc175627bf6 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php @@ -1,6 +1,6 @@ open(); + $dates = $reportStatistics->getGridBlock()->getRowsData(['updated_at']); + $currentDate = new \DateTime(); + $currentDate->setTimezone(new \DateTimeZone($_ENV['magento_timezone'])); + foreach ($dates as $date) { + \PHPUnit_Framework_Assert::assertContains( + $currentDate->format('M j, Y, g'), + date('M j, Y, g', strtotime($date['updated_at'])), + "Reports 'Updated' column values are displayed in an incorrect timezone." + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Reports 'Updated' column values are displayed in the correct timezone."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php index ba9597ea8672f..fdb0658049ef4 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php @@ -1,6 +1,6 @@ order = $order; + $this->searchInShippingReportGrid($shippingReport); + $shipmentResult = $this->salesShippingReport->getGridBlock()->getLastResult(); + $prepareInitialResults = $this->prepareExpectedResult($initialShippingResult, $shipmentResult); + list($prepareInitialResult, $shipmentResult) = $prepareInitialResults; + \PHPUnit_Framework_Assert::assertEquals( + $prepareInitialResult, + $shipmentResult, + "Shipment report interval result not contains actual data." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Shipment report interval result contains actual data.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportTotalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportTotalResult.php new file mode 100644 index 0000000000000..09d07d2f5dec9 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportTotalResult.php @@ -0,0 +1,47 @@ +order = $order; + $this->searchInShippingReportGrid($shippingReport); + $shipmentResult = $this->salesShippingReport->getGridBlock()->getTotalResult(); + $prepareInitialResults = $this->prepareExpectedResult($initialShippingTotalResult, $shipmentResult); + list($prepareInitialResult, $shipmentResult) = $prepareInitialResults; + \PHPUnit_Framework_Assert::assertEquals( + $prepareInitialResult, + $shipmentResult, + "Grand total Shipment result is not correct." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Shipment report grand total result contains actual data.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php index f6fbe871ff6a2..2aa8c515912af 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Bestsellers.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Bestsellers.xml index 8502e36121e28..d81959a3238bc 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Bestsellers.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Bestsellers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerAccounts.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerAccounts.xml index 04104783359fd..adc4ee1381a42 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerAccounts.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerAccounts.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerOrdersReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerOrdersReport.xml index 4b12064c512ef..5b993c904211b 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerOrdersReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerOrdersReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerReportReview.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerReportReview.xml index bb41843910694..05c89054eda37 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerReportReview.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerReportReview.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerTotalsReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerTotalsReport.xml index 777cc185c359c..90aa25bf9eaa3 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerTotalsReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/CustomerTotalsReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/DownloadsReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/DownloadsReport.xml index b7316ef267eba..1f59d72155c5d 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/DownloadsReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/DownloadsReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/OrderedProductsReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/OrderedProductsReport.xml index 7757b61a03330..75201a184dbdc 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/OrderedProductsReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/OrderedProductsReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductLowStock.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductLowStock.xml index 3601b03a316d2..39af1b2dcb692 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductLowStock.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductLowStock.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportReview.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportReview.xml index 4930001f8c42d..1d4251f791048 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportReview.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportReview.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportView.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportView.xml index 201af2944b8e8..8c10950b5885e 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportView.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ProductReportView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/RefundsReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/RefundsReport.xml index 0988690f58437..4caaeda3bef83 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/RefundsReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/RefundsReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesCouponReportView.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesCouponReportView.xml index 7840dfa1c1d3c..292e51a73c7f0 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesCouponReportView.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesCouponReportView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesInvoiceReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesInvoiceReport.xml index 3c04d1ffb2e8b..b76e92d5c4445 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesInvoiceReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesInvoiceReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesReport.xml index f0e9ffafdc8c8..b07174b6f9c8f 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesShippingReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesShippingReport.xml new file mode 100644 index 0000000000000..347cb3ed84f73 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesShippingReport.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesTaxReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesTaxReport.xml index 7f5a80c6934c7..62e2cbb767543 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesTaxReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SalesTaxReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SearchIndex.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SearchIndex.xml index 7fd4e0153a864..087e2a6ce5aac 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SearchIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/SearchIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ShopCartProductReport.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ShopCartProductReport.xml index 123fbff081682..1ba7977f21254 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ShopCartProductReport.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/ShopCartProductReport.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Statistics.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Statistics.xml index e916a4fe448cd..253b9b2d11d6a 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Statistics.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Page/Adminhtml/Statistics.xml @@ -1,12 +1,13 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/Repository/ConfigData.xml index b93e1ea8e31d0..b0731a61815ea 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -27,5 +27,17 @@ 12 + + + + Timezone + Australia/Sydney + + + store + website + custom_store + + diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/AbandonedCartsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/AbandonedCartsReportEntityTest.php index 5930e63b9d3bd..cf185a631ddb0 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/AbandonedCartsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/AbandonedCartsReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/BestsellerProductsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/BestsellerProductsReportEntityTest.php index 3eb5237eddd97..4a6c353d6defd 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/BestsellerProductsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/BestsellerProductsReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderCountReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderCountReportEntityTest.php index cacb6e5a329bf..4a54c5a929a82 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderCountReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderCountReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderTotalReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderTotalReportEntityTest.php index c366cedb3c3a9..5a029a81b8cab 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderTotalReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomersOrderTotalReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/DownloadProductsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/DownloadProductsReportEntityTest.php index 97dc365d62338..a38865f822dff 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/DownloadProductsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/DownloadProductsReportEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes downloadable_product 1 + to_maintain:yes two_downloadable_product 2 + to_maintain:yes downloadable_product 0 diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/LowStockProductsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/LowStockProductsReportEntityTest.php index 0dd87bde327c9..d0296fbe126b2 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/LowStockProductsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/LowStockProductsReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml index a933fc1f0e860..28397e18082af 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NewAccountsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NewAccountsReportEntityTest.php index bb5f8644d4359..7209e066eacf6 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NewAccountsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NewAccountsReportEntityTest.php @@ -1,6 +1,6 @@ + stable:no default 1 m/d/Y @@ -16,6 +17,7 @@ + stable:no default 1 m/d/Y @@ -24,6 +26,7 @@ + stable:no default 1 m/d/Y diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/OrderedProductsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/OrderedProductsReportEntityTest.php index 7d0d13862e772..94e7cfc4e371d 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/OrderedProductsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/OrderedProductsReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php index 148c0a69cecaa..b0f88e7f3ae46 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductsInCartReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/RefreshReportsStatisticsTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/RefreshReportsStatisticsTest.php new file mode 100644 index 0000000000000..d45e772ebe329 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/RefreshReportsStatisticsTest.php @@ -0,0 +1,82 @@ + Refresh Statistics. + * 3. Select all reports. + * 4. Update statistics. + * 5. Perform all assertions. + * + * @group Reports + * @ZephyrId MAGETWO-40919 + */ +class RefreshReportsStatisticsTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + /* end tags */ + + /** + * Reports Statistics page. + * + * @var Statistics + */ + protected $reportStatistics; + + /** + * Factory for Test Steps. + * + * @var TestStepFactory + */ + protected $testStepFactory; + + /** + * Inject pages. + * + * @param TestStepFactory $testStepFactory + * @param Statistics $reportStatistics + * @return void + */ + public function __inject( + TestStepFactory $testStepFactory, + Statistics $reportStatistics + ) { + $this->testStepFactory = $testStepFactory; + $this->reportStatistics = $reportStatistics; + } + + /** + * Refresh reports statistics. + * + * @param string $action + * @param string $configData + * @return void + */ + public function test($action, $configData) + { + // Preconditions + $this->testStepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); + + // Test steps + $this->reportStatistics->open(); + $this->reportStatistics->getGridBlock()->massaction([], $action, true, 'Select All'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/RefreshReportsStatisticsTest.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/RefreshReportsStatisticsTest.xml new file mode 100644 index 0000000000000..13528a9866314 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/RefreshReportsStatisticsTest.xml @@ -0,0 +1,25 @@ + + + + + + MAGETWO-63069 Reports feature Refresh Lifetime Statistics does not work on Magento with split DB + Refresh Statistics for the Last Day + website_with_custom_timezone + + + + + MAGETWO-63069 Reports feature Refresh Lifetime Statistics does not work on Magento with split DB + Refresh Lifetime Statistics + website_with_custom_timezone + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.php index 376e5662320b8..b4e80002a8e35 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesCouponReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesCouponReportEntityTest.php index 0d59b989fc25f..d0b76c3c86db2 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesCouponReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesCouponReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesInvoiceReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesInvoiceReportEntityTest.php index 3ebfd4746a858..f34df836ff891 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesInvoiceReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesInvoiceReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesOrderReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesOrderReportEntityTest.php index c1eb4e8b35c3f..15cc2742d8e0c 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesOrderReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesOrderReportEntityTest.php @@ -1,6 +1,6 @@ @@ -21,6 +21,7 @@ + stable:no default full_invoice Order Created @@ -34,6 +35,7 @@ + stable:no default full_invoice Order Updated diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesRefundsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesRefundsReportEntityTest.php index 692e9024a2212..fe2140f452e36 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesRefundsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesRefundsReportEntityTest.php @@ -1,6 +1,6 @@ @@ -20,6 +20,7 @@ + stable:no assert refunds month report default full_invoice @@ -32,6 +33,7 @@ + stable:no assert refund Daily report default full_invoice diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesTaxReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesTaxReportEntityTest.php index 0d5249ef4d06f..d7e5912c3dcdb 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesTaxReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SalesTaxReportEntityTest.php @@ -1,6 +1,6 @@ @@ -22,6 +22,7 @@ + stable:no invoice custom_rule default @@ -37,6 +38,7 @@ + stable:no invoice,shipment custom_rule default diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SearchTermsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SearchTermsReportEntityTest.php index 1175942452f89..2b2e52b304cd9 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SearchTermsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/SearchTermsReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ViewedProductsReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ViewedProductsReportEntityTest.php index 905fa8fb70f0c..e036c6e3a51cd 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ViewedProductsReportEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ViewedProductsReportEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Customer/Edit/Tab/Reviews.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Customer/Edit/Tab/Reviews.php index 9f931570d441f..bb02ad421e8af 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Customer/Edit/Tab/Reviews.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Customer/Edit/Tab/Reviews.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php new file mode 100644 index 0000000000000..ffefaa817e6ef --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/Product/Grid.php @@ -0,0 +1,29 @@ + [ + 'selector' => 'input[name="title"]', + ], + 'sku' => [ + 'selector' => 'input[name="sku"]', + ], + ]; +} diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php index 3ba4369fb0fcc..2dc54452f7724 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Edit/RatingElement.php @@ -1,6 +1,6 @@ blockFactory->create( - \Magento\Review\Test\Block\Adminhtml\Product\Grid::class, + \Magento\Review\Test\Block\Adminhtml\Edit\Product\Grid::class, ['element' => $this->_rootElement->find($this->reviews)] ); } diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php index 55060e7a85db9..91791aad33897 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Product/Grid.php @@ -1,18 +1,25 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Edit/RatingForm.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Edit/RatingForm.php index c2358bd5e7be7..23a165ddf4df2 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Edit/RatingForm.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Edit/RatingForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Grid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Grid.php index 7e0d1ee86622c..4bfe4454e3ed8 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Adminhtml/Rating/Grid.php @@ -1,6 +1,6 @@ @@ -20,7 +20,7 @@ textarea - #detailed_rating + #rating_detail Magento\Review\Test\Block\Adminhtml\Edit\RatingElement diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Product/View.php b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Product/View.php index 1628db7bff231..2a755074c8786 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Block/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Block/Product/View.php @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php index 9b4b7081c385c..46ab998733419 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review.xml index 7da5f657f7b15..192ed145ca6cc 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review/EntityId.php b/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review/EntityId.php index f4e5496f734fb..b29c3e18607b8 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review/EntityId.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Review/EntityId.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingIndex.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingIndex.xml index 00681900c018a..0905e5d2a701a 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingNew.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingNew.xml index a74db26fc9725..71f61c983d8f2 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingNew.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/RatingNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewEdit.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewEdit.xml index ebb083878eb35..bd670511d0742 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewIndex.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewIndex.xml index 66caff9b5a163..528761d8618db 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Adminhtml/ReviewIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Product/CatalogProductView.xml index 0d9a18c3eb679..8bbe7b9cb4ce7 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Rating.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Rating.xml index 949e9b7d0668d..57d192761cae5 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Rating.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Rating.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml index 05c96f78ad783..aea9c9a349b3b 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest.php index 648de4bf40183..a2835fb72e29c 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php index aeeff3480e4a6..8773abf36bebf 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.php @@ -1,6 +1,6 @@ getDataFieldConfig('entity_id')['source']->getEntity(); - $filter = ['id' => $product->getId()]; + $filter = ['sku' => $product->getSku()]; $this->review = $review; // Steps: $this->reviewIndex->open(); $this->reviewIndex->getReviewActions()->addNew(); - $this->reviewEdit->getProductGrid()->searchAndOpen($filter); + $this->reviewEdit->getProductGrid()->search($filter); + $this->reviewEdit->getProductGrid()->openFirstRow(); $this->reviewEdit->getReviewForm()->fill($this->review); $this->reviewEdit->getPageActions()->save(); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.xml b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.xml index a44ea2b6153fb..9b9274451cdca 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewBackendEntityTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewFrontendEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewFrontendEntityTest.php index 2e764636789e1..7bf40015bd263 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewFrontendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductReviewFrontendEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes Guest name_%isolation% title_%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest.php index 316af94078849..49c250856e85e 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ManageProductReviewFromCustomerPageTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ManageProductReviewFromCustomerPageTest.php index fc58266356223..268d69e441852 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ManageProductReviewFromCustomerPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ManageProductReviewFromCustomerPageTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/MassActionsProductReviewEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/MassActionsProductReviewEntityTest.php index 027b299e71072..72d52953410a3 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/MassActionsProductReviewEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/MassActionsProductReviewEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ModerateProductReviewEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ModerateProductReviewEntityTest.php index dbe89b387e615..c62dba4539c0d 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ModerateProductReviewEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/ModerateProductReviewEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml index 9d039c470e4f5..ccb76463f9bab 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityOnProductPageTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityOnProductPageTest.php index 9f343bdfc10fe..25d733a0996f2 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityOnProductPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityOnProductPageTest.php @@ -1,6 +1,6 @@ + to_maintain:yes 3 Approved Main Website/Main Website Store/Default Store View diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityTest.php index a5901a6211a25..d77a92e2400f3 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/UpdateProductReviewEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes review_for_simple_product_with_rating name_upd_%isolation% title_upd_%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Review/Test/etc/curl/di.xml index 2e4d21c9f521d..27054035616ca 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Review/Test/etc/di.xml index a8c3eb3c4b727..1d073a95dc150 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Review/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/CreditMemo/Grid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/CreditMemo/Grid.php index 60a47275e18a1..67d661615cddb 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/CreditMemo/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/CreditMemo/Grid.php @@ -1,6 +1,6 @@ prepareData($data); if (isset($data['items_data']) && $products !== null) { - foreach ($products as $key => $product) { - $this->getItemsBlock()->getItemProductBlock($product)->fillProduct($data['items_data'][$key]); + foreach ($data['items_data'] as $key => $item) { + $productSku = $products[$key]->getData()['sku']; + $this->getItemsBlock()->getItemProductBlock($productSku)->fillProduct($item); } } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractForm/Product.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractForm/Product.php index a23d423a2422b..68e4a12a78446 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractForm/Product.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractForm/Product.php @@ -1,6 +1,6 @@ parseProductName($item->find($this->product)->getText()); + $itemData['product'] = preg_replace('/\n|\r/', '', $item->find($this->title)->getText()); + $itemData['sku'] = $this->getSku($item); $itemData['price'] = $this->escapePrice($item->find($this->price)->getText()); - $itemData['qty'] = $item->find($this->qty)->getText(); + $itemData['qty'] = $this->getQty($item); $itemData['subtotal'] = $this->escapePrice($item->find($this->subtotal)->getText()); $itemData['tax'] = $this->escapePrice($item->find($this->taxAmount)->getText()); $itemData['discount'] = $this->escapePrice($item->find($this->discountAmount)->getText()); @@ -97,18 +113,33 @@ public function getData() } /** - * Parse product name to title and sku product. + * Get product quantity. * - * @param string $product - * @return array + * @param ElementInterface $item + * @return null|int */ - protected function parseProductName($product) + protected function getQty(ElementInterface $item) { - $data = array_map('trim', explode('SKU:', str_replace("\n", '', $product))); - return [ - 'product' => $data[0], - 'sku' => isset($data[1]) ? $data[1] : '' - ]; + $qty = null; + $elements = $item->getElements($this->qty); + foreach ($elements as $element) { + $qty += (int) $element->getText(); + } + return $qty; + } + + /** + * Get product SKU. + * + * @param ElementInterface $item + * @return string + */ + protected function getSku(ElementInterface $item) + { + $itemContent = $item->find($this->sku)->getText(); + $itemContent = preg_replace('/\n|\r/', '', $itemContent); + $itemContent = str_replace('SKU: ', '', $itemContent); + return $itemContent; } /** @@ -117,8 +148,23 @@ protected function parseProductName($product) * @var string $price * @return string */ - protected function escapePrice($price) + private function escapePrice($price) { return preg_replace('[^0-9\.]', '', $price); } + + /** + * Parse product name to title and sku product. + * + * @param string $product + * @return array + */ + protected function parseProductName($product) + { + $data = array_map('trim', explode('SKU:', str_replace("\n", '', $product))); + return [ + 'product' => $data[0], + 'sku' => isset($data[1]) ? $data[1] : '' + ]; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItemsNewBlock.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItemsNewBlock.php index 2ba8fe00f1e71..71c560894cdf7 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItemsNewBlock.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/AbstractItemsNewBlock.php @@ -1,6 +1,6 @@ _rootElement->find($this->cancel)->click(); - $element = $this->browser->find($this->confirmModal); - /** @var \Magento\Ui\Test\Block\Adminhtml\Modal $modal */ - $modal = $this->blockFactory->create(\Magento\Ui\Test\Block\Adminhtml\Modal::class, ['element' => $element]); - $modal->acceptAlert(); + $this->acceptAlert(); } /** @@ -202,6 +199,7 @@ public function sendEmail() public function void() { $this->_rootElement->find($this->void)->click(); + $this->acceptAlert(); } /** @@ -266,27 +264,36 @@ public function isActionButtonVisible($buttonName) } /** - * Accept order + * Accept order. + * * @return void */ public function accept() { $acceptPayment = '#accept_payment'; $this->_rootElement->find($acceptPayment)->click(); - $element = $this->browser->find($this->confirmModal); - /** @var Modal $modal */ - $modal = $this->blockFactory->create(Modal::class, ['element' => $element]); - $modal->acceptAlert(); + $this->acceptAlert(); } /** - * Deny order + * Deny order. + * * @return void */ public function deny() { $denyPayment = '#deny_payment'; $this->_rootElement->find($denyPayment)->click(); + $this->acceptAlert(); + } + + /** + * Accept alert. + * + * @return void + */ + private function acceptAlert() + { $element = $this->browser->find($this->confirmModal); /** @var Modal $modal */ $modal = $this->blockFactory->create(Modal::class, ['element' => $element]); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php index 874fe2844c476..355205784d56a 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php @@ -1,6 +1,6 @@ blockFactory->create( \Magento\Sales\Test\Block\Adminhtml\Order\Create\Billing\Method::class, @@ -279,20 +279,22 @@ public function updateItems() } /** - * Fill addresses based on present data in customer and order fixtures. + * Fill Billing Address. * - * @param FixtureInterface $address - * @param string $saveAddress + * @param FixtureInterface $billingAddress + * @param string $saveAddress [optional] * @param bool $setShippingAddress [optional] * @return void */ - public function fillAddresses(FixtureInterface $address, $saveAddress = 'No', $setShippingAddress = true) - { - if ($setShippingAddress) { + public function fillBillingAddress( + FixtureInterface $billingAddress, + $saveAddress = 'No', + $setShippingAddress = true + ) { + if ($setShippingAddress !== false) { $this->getShippingAddressBlock()->uncheckSameAsBillingShippingAddress(); } - $this->browser->find($this->header)->hover(); - $this->getBillingAddressBlock()->fill($address); + $this->getBillingAddressBlock()->fill($billingAddress); $this->getBillingAddressBlock()->saveInAddressBookBillingAddress($saveAddress); $this->getTemplateBlock()->waitLoader(); if ($setShippingAddress) { @@ -301,6 +303,18 @@ public function fillAddresses(FixtureInterface $address, $saveAddress = 'No', $s } } + /** + * Fill Shipping Address. + * + * @param FixtureInterface $shippingAddress + * @return void + */ + public function fillShippingAddress(FixtureInterface $shippingAddress) + { + $this->getShippingAddressBlock()->fill($shippingAddress); + $this->getTemplateBlock()->waitLoader(); + } + /** * Select shipping method. * @@ -325,6 +339,7 @@ public function selectPaymentMethod(array $paymentCode, InjectableFixture $credi $this->getTemplateBlock()->waitLoader(); $this->_rootElement->find($this->orderMethodsSelector)->click(); $this->getBillingMethodBlock()->selectPaymentMethod($paymentCode, $creditCard); + $this->_rootElement->click(); $this->getTemplateBlock()->waitLoader(); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Address.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Address.php index b23ba296fbb19..7b9713078011a 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Address.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Address.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php index 280211c7ef20f..b2955e48124f3 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php @@ -1,13 +1,14 @@ _rootElement->find(sprintf($this->paymentMethod, $paymentCode['method'])); + $paymentMethod = $payment['method']; + $paymentInput = $this->_rootElement->find(sprintf($this->paymentMethod, $paymentMethod)); if ($paymentInput->isVisible()) { $paymentInput->click(); $this->waitForElementNotVisible($this->loader); } - if (isset($paymentCode['po_number'])) { - $this->_rootElement->find($this->purchaseOrderNumber)->setValue($paymentCode['po_number']); + if (isset($payment['po_number'])) { + $this->_rootElement->find($this->purchaseOrderNumber)->setValue($payment['po_number']); } if ($creditCard !== null) { - $class = explode('\\', get_class($creditCard)); - $module = $class[1]; - /** @var \Magento\Payment\Test\Block\Form\Cc $formBlock */ + $module = $creditCard->hasData('payment_code') ? ucfirst($creditCard->getPaymentCode()) : 'Payment'; + /** @var \Magento\Payment\Test\Block\Form\PaymentCc $formBlock */ $formBlock = $this->blockFactory->create( - "\\Magento\\{$module}\\Test\\Block\\Form\\Cc", - ['element' => $this->_rootElement->find('#payment_form_' . $paymentCode['method'])] + "\\Magento\\{$module}\\Test\\Block\\Form\\{$module}Cc", + ['element' => $this->_rootElement->find('#payment_form_' . $paymentMethod)] ); $formBlock->fill($creditCard); } } + + /** + * @return array + */ + public function getJsErrors() + { + $data = []; + $elements = $this->_rootElement->getElements($this->mageErrorField, Locator::SELECTOR_XPATH); + foreach ($elements as $error) { + if ($error->isVisible()) { + $label = $error->find($this->errorLabelPrecedingField, Locator::SELECTOR_XPATH); + $label = $label->getAttribute('name'); + $label = preg_replace('/payment\[(.*)\]/u', '$1', $label); + $data[$label] = $error->getText(); + } + } + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Coupons.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Coupons.php index a68b9f52dc8d0..8cf8bff45ad02 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Coupons.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Coupons.php @@ -1,6 +1,6 @@ getName(); $this->_rootElement->find(sprintf($this->addToOrderProductName, $name), Locator::SELECTOR_XPATH)->click(); - $this->_rootElement->click(); - $this->_rootElement->find(sprintf($this->addToOrder, $name), Locator::SELECTOR_XPATH, 'checkbox') - ->setValue('Yes'); + + $dataConfig = $product->getDataConfig(); + $typeId = isset($dataConfig['type_id']) ? $dataConfig['type_id'] : null; + + if ($this->hasRender($typeId)) { + $this->_rootElement->find(sprintf($this->addToOrderConfigure, $name), Locator::SELECTOR_XPATH)->click(); + $this->callRender($typeId, 'configProduct', ['product' => $product]); + } else { + $this->_rootElement->click(); + $this->_rootElement->find(sprintf($this->addToOrder, $name), Locator::SELECTOR_XPATH, 'checkbox') + ->setValue('Yes'); + } } } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar/LastOrderedItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar/LastOrderedItems.php index 758343f60cf93..e3c7b9255d33c 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar/LastOrderedItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/CustomerActivities/Sidebar/LastOrderedItems.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php index 69ef66d947597..3f72e8d1aa629 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Search/Grid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Search/Grid.php index 7ce93c59edabe..d33cb1f969454 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Search/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Search/Grid.php @@ -1,6 +1,6 @@ $this->_rootElement->find($this->templateBlock, Locator::SELECTOR_XPATH)] ); } + + /** + * Fill specified form data. + * + * @param array $fields + * @param SimpleElement $element + * @return void + * @throws \Exception + */ + protected function _fill(array $fields, SimpleElement $element = null) + { + $context = ($element === null) ? $this->_rootElement : $element; + foreach ($fields as $name => $field) { + $this->waitFormLoading(); + $element = $this->getElement($context, $field); + if (!$element->isDisabled()) { + $element->setValue($field['value']); + } else { + throw new \Exception("Unable to set value to field '$name' as it's disabled."); + } + } + } + + /** + * Wait for form loading. + * + * @return void + */ + private function waitFormLoading() + { + $this->_rootElement->click(); + $this->browser->waitUntil( + function () { + return $this->browser->find($this->waitElement)->isVisible() ? null : true; + } + ); + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Address.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Address.xml new file mode 100644 index 0000000000000..3eeead128a1ed --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Address.xml @@ -0,0 +1,27 @@ + + + + order[shipping_address] + + + + + + [name='order[shipping_address][street][0]'] + + + + select + + + select + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php index 3d9673e29805d..5e1bcd20ee9cc 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php @@ -1,6 +1,6 @@ waitFormLoading(); if ($this->_rootElement->find($this->shippingMethodsLink)->isVisible()) { $this->_rootElement->find($this->shippingMethodsLink)->click(); } @@ -46,4 +54,19 @@ public function selectShippingMethod(array $shippingMethod) ); $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->click(); } + + /** + * Wait for form loading. + * + * @return void + */ + private function waitFormLoading() + { + $this->_rootElement->click(); + $this->browser->waitUntil( + function () { + return $this->browser->find($this->waitElement)->isVisible() ? null : true; + } + ); + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Store.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Store.php index a40acf52f4bc0..49d09b30257f9 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Store.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Store.php @@ -1,6 +1,6 @@ _rootElement->find($this->submitOrder)->click(); } + + /** + * Get Order totals. + * + * @return array + */ + public function getOrderTotals() + { + $totals = []; + $elements = $this->_rootElement->getElements($this->totalsRowsLocator); + foreach ($elements as $row) { + if ($row->isVisible()) { + $key = trim($row->find($this->totalsRowKeyLocator)->getText()); + $value = $row->find($this->totalsRowValueLocator)->getText(); + $totals[$key] = $value; + } + } + return $totals; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form.php index ffac9ddff9932..1d570b5af9e10 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php index 52ff585cc43d6..a1c4000e36f26 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items.php @@ -1,6 +1,6 @@ productItems, $product->getSku()); + $selector = sprintf($this->productItems, $productSku); return $this->blockFactory->create( \Magento\Sales\Test\Block\Adminhtml\Order\Creditmemo\Form\Items\Product::class, ['element' => $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)] diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items/Product.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items/Product.php index 7fc7f056c2492..3da50e9a76533 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items/Product.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Form/Items/Product.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Grid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Grid.php index 7d1c46e4af49f..5fb370d2a6647 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Creditmemo/Grid.php @@ -1,6 +1,6 @@ openFilterBlock(); $storeGroupElements = $this->_rootElement->find($this->filters['purchase_point']['selector']) - ->getElements('//option/preceding-sibling::optgroup[1]', Locator::SELECTOR_XPATH); + ->getElements('.//option/preceding-sibling::optgroup[1]', Locator::SELECTOR_XPATH); $result = []; foreach ($storeGroupElements as $storeGroupElement) { diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/History.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/History.php deleted file mode 100644 index 2235122955a72..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/History.php +++ /dev/null @@ -1,121 +0,0 @@ -waitCommentsHistory(); - return $this->_rootElement->find($this->commentHistory, Locator::SELECTOR_CSS)->getText(); - } - - /** - * Get the authorized amount from the comments history. - * - * @return string - */ - public function getAuthorizedAmount() - { - $this->waitCommentsHistory(); - return $this->_rootElement->find($this->authorizedAmount, Locator::SELECTOR_XPATH)->getText(); - } - - /** - * Get the captured amount from the comments history. - * - * @return array - */ - public function getCapturedAmount() - { - $result = []; - $this->waitCommentsHistory(); - $captureComments = $this->_rootElement->getElements($this->capturedAmount, Locator::SELECTOR_XPATH); - foreach ($captureComments as $captureComment) { - $result[] = $captureComment->getText(); - } - return $result; - } - - /** - * Get the refunded amount from the comments history. - * - * @return array - */ - public function getRefundedAmount() - { - $result = []; - $this->waitCommentsHistory(); - $refundedComments = $this->_rootElement->getElements($this->refundedAmount, Locator::SELECTOR_XPATH); - foreach ($refundedComments as $refundedComment) { - $result[] = $refundedComment->getText(); - } - return $result; - } - - /** - * Wait for comments history is visible. - * - * @return void - */ - protected function waitCommentsHistory() - { - $element = $this->_rootElement; - $selector = $this->noteList; - $element->waitUntil( - function () use ($element, $selector) { - return $element->find($selector)->isVisible() ? true : null; - } - ); - } -} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form.php index 320d48eb195a9..6a6a1bd1ecff9 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items.php index baee80abd72df..c97807ccc1522 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items.php @@ -1,6 +1,6 @@ productItem, $product->getSku()); + $selector = sprintf($this->productItem, $productSku); return $this->blockFactory->create( \Magento\Sales\Test\Block\Adminhtml\Order\Invoice\Form\Items\Product::class, ['element' => $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)] diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items/Product.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items/Product.php index 2268bb206d176..f2b8776207f27 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items/Product.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Form/Items/Product.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Grid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Grid.php index c1c92dbc80b86..77c62febc152b 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/Grid.php @@ -1,6 +1,6 @@ _rootElement->find($this->capture, Locator::SELECTOR_CSS, 'select')->setValue($option); } + + /** + * Get message that invoice can be created only offline. + * + * @return null|string + */ + public function getCaptureOfflineMessage() + { + $captureCaseMessage = $this->_rootElement->find($this->captureOfflineMessage, Locator::SELECTOR_XPATH); + return $captureCaseMessage->isVisible() ? $captureCaseMessage->getText() : null; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/View/Items.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/View/Items.php index 60f2885494dc8..acf96e3f82219 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/View/Items.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Invoice/View/Items.php @@ -1,6 +1,6 @@ parseProductName($item->find($this->product)->getText()); - $itemData['qty'] = $item->find($this->qty)->getText(); + $itemData['product'] = preg_replace('/\n|\r/', '', $item->find($this->title)->getText()); + $itemData['sku'] = $this->getSku($item); + $itemData['qty'] = $this->getQty($item); $data[] = $itemData; } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/Assign/AssignForm.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/Assign/AssignForm.php index 1f25d28cd2afd..6336d4aeb0629 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/Assign/AssignForm.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/Assign/AssignForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/GridPageActions.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/GridPageActions.php index 606d5f51d1ac6..9ded06c9bee0c 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/GridPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Status/GridPageActions.php @@ -1,6 +1,6 @@ _rootElement->find($this->billingAddress, Locator::SELECTOR_CSS)->getText(); + } + + /** + * Get customer's shipping address from the data inside block. + * + * @return string + */ + public function getCustomerShippingAddress() + { + return $this->_rootElement->find($this->shippingAddress, Locator::SELECTOR_CSS)->getText(); + } + + /** + * Checks if new address button is visible. + * + * @return bool + */ + public function isNewAddressButtonVisible() + { + $button = $this->_rootElement->find($this->newAddressButton); + return $button->isVisible(); + } + + /** + * Clicks new address button. + * + * @return void + */ + public function clickNewAddressButton() + { + $this->_rootElement->find($this->newAddressButton)->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Info.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Info.php index a2535e9a98e0e..857b0c4bd61b7 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Info.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Info.php @@ -1,6 +1,6 @@ _rootElement->find($this->group, Locator::SELECTOR_XPATH)->getText(); } + + /** + * Get Product options + * + * @param int $sku + * @return array + */ + public function getProductOptions($sku) + { + $selector = str_replace('{SKU}', $sku, $this->itemOptions); + $productOption = $this->_rootElement->find($selector, Locator::SELECTOR_XPATH); + $result = []; + if ($productOption->isPresent()) { + $keyItem = $productOption->getElements('dt'); + $valueItem = $productOption->getElements('dd'); + foreach ($keyItem as $key => $item) { + $result[$item->getText()] = null; + if (isset($valueItem[$key])) { + $result[$item->getText()] = $valueItem[$key]->getText(); + } + } + } + return $result; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Items.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Items.php index 8699e42f9d129..e67e6fff487e6 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Items.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Items.php @@ -1,6 +1,6 @@ blockFactory->create( - \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info::class, - ['element' => $this->_rootElement->find($this->orderInfoBlock)] - ); - } + // } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml index 383dfb8b7b6aa..bfc1fdab48f49 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/OrderForm.xml @@ -1,11 +1,16 @@ + + Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info + #sales_order_view_tabs_order_info + css selector + Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Invoices #sales_order_view_tabs_order_invoices diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php index 148292da25704..b4c52d97e8009 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/CreditMemos.php @@ -1,6 +1,6 @@ _rootElement->find($this->editLink)->getText(); + $this->resetFilter(); + $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH); + return $this->_rootElement->find($this->creditMemoId)->getText(); } /** - * Get credit memo ids + * Get credit memo ids. * * @return array */ public function getIds() { $result = []; - $creditMemoIds = $this->_rootElement->getElements($this->editLink); + $this->resetFilter(); + $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH); + $creditMemoIds = $this->_rootElement->getElements($this->creditMemoId); foreach ($creditMemoIds as $creditMemoId) { $result[] = trim($creditMemoId->getText()); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php index 50c5a077e9b55..85aa0665414b0 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info.php @@ -1,27 +1,43 @@ _rootElement->find($this->orderStatus)->getText(); } + + /** + * Returns Payment Information block. + * + * @return PaymentInfoBlock + */ + public function getPaymentInfoBlock() + { + return $this->blockFactory->create( + PaymentInfoBlock::class, + ['element' => $this->_rootElement->find($this->paymentInfoBlockSelector)] + ); + } + + /** + * Returns Comments history block. + * + * @return CommentsHistoryBlock + */ + public function getCommentsHistoryBlock() + { + return $this->blockFactory->create( + CommentsHistoryBlock::class, + ['element' => $this->_rootElement->find($this->commentsHistoryBlockSelector)] + ); + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/CommentsHistoryBlock.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/CommentsHistoryBlock.php new file mode 100644 index 0000000000000..9daed9e87482c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/CommentsHistoryBlock.php @@ -0,0 +1,93 @@ +_rootElement->getElements($this->commentHistory); + foreach ($elements as $key => $item) { + $result[$key] = [ + 'date' => $item->find($this->commentHistoryDate)->getText(), + 'time' => $item->find($this->commentHistoryTime)->getText(), + 'status' => $item->find($this->commentHistoryStatus)->getText(), + 'is_customer_notified' => $item->find($this->commentHistoryNotifiedStatus)->getText(), + 'comment' => '', + ]; + if ($item->find($this->comment)->isVisible()) { + $result[$key]['comment'] = $item->find($this->comment)->getText(); + } + } + + return $result; + } + + /** + * Get last comment. + * + * @return array + */ + public function getLatestComment() + { + $comments = $this->getComments(); + return current($comments); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/PaymentInfoBlock.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/PaymentInfoBlock.php new file mode 100644 index 0000000000000..0d38cf5e19c05 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Info/PaymentInfoBlock.php @@ -0,0 +1,40 @@ +_rootElement->getElements($this->info); + foreach ($elements as $row) { + $key = rtrim($row->find('th')->getText(), ':'); + $value = $row->find('td')->getText(); + $result[$key] = $value; + } + + return $result; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices.php index 69ea64754ac80..d7d31d28e0e4e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Invoices.php @@ -1,6 +1,6 @@ [ 'selector' => 'input[name="increment_id"]', ], + 'order_id' => [ + 'selector' => 'input[name="order_increment_id"]', + ], 'status' => [ 'selector' => 'select[name="state"]', 'input' => 'select', @@ -54,6 +66,7 @@ class Grid extends \Magento\Backend\Test\Block\Widget\Grid public function getIds() { $result = []; + $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH); $invoiceIds = $this->_rootElement->getElements($this->invoiceId); foreach ($invoiceIds as $invoiceId) { $result[] = trim($invoiceId->getText()); @@ -69,6 +82,7 @@ public function getIds() */ public function viewInvoice() { + $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH); $this->_rootElement->find($this->invoiceId)->click(); } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php index 0710933ebe08e..213583f75b731 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Shipments.php @@ -1,6 +1,6 @@ [ - 'selector' => 'input[name="real_shipment_id"]', + 'selector' => 'input[name="increment_id"]', ], 'qty_from' => [ 'selector' => '[name="total_qty[from]"]', @@ -44,13 +53,14 @@ class Grid extends \Magento\Backend\Test\Block\Widget\Grid ]; /** - * Get shipment ids + * Get shipment ids. * * @return array */ public function getIds() { $result = []; + $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH); $shipmentIds = $this->_rootElement->getElements($this->shipmentId); foreach ($shipmentIds as $shipmentId) { $result[] = trim($shipmentId->getText()); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Transactions.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Transactions.php index 80309405fcd05..bfc43e510ecfe 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Transactions.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/View/Tab/Transactions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Order/History.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Order/History.php index 244da3f9150ca..ab2e578680b4d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Order/History.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Order/History.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php index 26978343fb2c2..d98bf2b7c3236 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertItems.php @@ -1,30 +1,30 @@ getEntityId()['products']; $productsData = []; - - /** @var CatalogProductSimple $product */ - foreach ($products as $key => $product) { + if ($cart === null) { + $cart['data']['items'] = ['products' => $order->getEntityId()['products']]; + $fixtureFactory = $this->objectManager->create(FixtureFactory::class); + $cart = $fixtureFactory->createByCode('cart', $cart); + } + /** @var \Magento\Catalog\Test\Fixture\Cart\Item $item */ + foreach ($cart->getItems() as $key => $item) { $productsData[] = [ - 'product' => $product->getName(), - 'sku' => $product->getSku(), + 'product' => $item->getData()['name'], + 'sku' => $item->getData()['sku'], 'qty' => (isset($data[$key]['qty']) && $data[$key]['qty'] != '-') ? $data[$key]['qty'] - : $product->getCheckoutData()['qty'], + : $item->getData()['qty'], ]; } @@ -61,7 +65,7 @@ protected function prepareOrderProducts(OrderInjectable $order, array $data = nu } /** - * Prepare invoice data + * Prepare invoice data. * * @param array $itemsData * @return array diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertOrderOnFrontend.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertOrderOnFrontend.php index 01157079e07d2..10c223de7e764 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertOrderOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AbstractAssertOrderOnFrontend.php @@ -1,6 +1,6 @@ open(); $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - $history = $orderView->getOrderHistoryBlock()->getCommentsHistory(); - \PHPUnit_Framework_Assert::assertContains(self::$message, $history); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); + + \PHPUnit_Framework_Assert::assertContains(self::$message, $latestComment['comment']); } /** - * @inheritdoc + * Returns a string representation of the object. + * + * @return string */ public function toString() { diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php index fefc148b8bd03..0d6066f0cea8b 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php @@ -1,6 +1,6 @@ open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - $actualAuthorizedAmount = $salesOrderView->getOrderHistoryBlock()->getAuthorizedAmount(); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); - \PHPUnit_Framework_Assert::assertContains( - self::AUTHORIZED_AMOUNT . $prices['grandTotal'], - $actualAuthorizedAmount, + \PHPUnit_Framework_Assert::assertRegExp( + sprintf(self::AUTHORIZED_AMOUNT_PATTERN, $prices['grandTotal']), + $latestComment['comment'], 'Incorrect authorized amount value for the order #' . $orderId ); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php index c46a161cc6372..11087c98bf0f8 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php @@ -1,6 +1,6 @@ open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - $actualCapturedAmount = $salesOrderView->getOrderHistoryBlock()->getCapturedAmount(); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $comments = $infoTab->getCommentsHistoryBlock()->getComments(); + + foreach ($comments as $key => $comment) { + if (strstr($comment['comment'], 'Captured') === false) { + unset($comments[$key]); + } + } + $comments = array_values($comments); + foreach ($capturedPrices as $key => $capturedPrice) { - \PHPUnit_Framework_Assert::assertContains( - self::CAPTURED_AMOUNT . $capturedPrice, - $actualCapturedAmount[$key], + \PHPUnit_Framework_Assert::assertRegExp( + sprintf(self::CAPTURED_AMOUNT_PATTERN, $capturedPrice), + $comments[$key]['comment'], 'Incorrect captured amount value for the order #' . $orderId ); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php index c4978b44cd6d7..09dbbc12a7056 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php @@ -1,6 +1,6 @@ open(); $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - $history = $orderView->getOrderHistoryBlock()->getCommentsHistory(); - \PHPUnit_Framework_Assert::assertContains(self::$message, $history); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); + + \PHPUnit_Framework_Assert::assertContains(self::$message, $latestComment['comment']); } /** - * @inheritdoc + * Returns a string representation of the object. + * + * @return string */ public function toString() { diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php index b6dbfdf1a6702..0e9ee58c19fb3 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php @@ -1,6 +1,6 @@ getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); $salesOrderView->getOrderForm()->openTab('invoices'); /** @var Grid $grid */ - $grid = $salesOrderView->getOrderForm()->getTab('invoices')->getGridBlock(); + $grid = $salesOrderView->getOrderInvoiceGrid(); $amount = $order->getPrice(); foreach ($ids['invoiceIds'] as $key => $invoiceId) { $filter = [ 'id' => $invoiceId, - 'amount_from' => $amount[$key]['grand_invoice_total'], - 'amount_to' => $amount[$key]['grand_invoice_total'], + 'grand_total_from' => $amount[$key]['grand_invoice_total'], + 'grand_total_to' => $amount[$key]['grand_invoice_total'], ]; $grid->search($filter); $filter['amount_from'] = number_format($amount[$key]['grand_invoice_total'], 2); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php index 9b43a3917aac1..abcf3a9c55d7b 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php @@ -1,11 +1,12 @@ getId(); - $productsData = $this->prepareOrderProducts($order, $data['items_data']); + $productsData = $this->prepareOrderProducts($order, $data['items_data'], $cart); foreach ($ids['invoiceIds'] as $invoiceId) { $filter = [ 'order_id' => $orderId, diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceNotInInvoicesGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceNotInInvoicesGrid.php new file mode 100644 index 0000000000000..1139bf39e413d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceNotInInvoicesGrid.php @@ -0,0 +1,61 @@ +open(); + $amount = $order->getPrice(); + $orderId = $order->getId(); + foreach ($ids['invoiceIds'] as $key => $invoiceId) { + $filter = [ + 'id' => $invoiceId, + 'order_id' => $orderId, + 'grand_total_from' => $amount[$key]['grand_invoice_total'], + 'grand_total_to' => $amount[$key]['grand_invoice_total'], + ]; + $invoiceIndex->getInvoicesGrid()->search($filter); + $filter['grand_total_from'] = number_format($amount[$key]['grand_invoice_total'], 2); + $filter['grand_total_to'] = number_format($amount[$key]['grand_invoice_total'], 2); + \PHPUnit_Framework_Assert::assertFalse( + $invoiceIndex->getInvoicesGrid()->isRowVisible($filter, false, false), + 'Invoice is present in invoices grid on invoice index page.' + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Invoice is absent in the invoices grid on invoice index page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php new file mode 100644 index 0000000000000..856b352bb11c6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php @@ -0,0 +1,53 @@ +open(['order_id' => $orderId]); + $salesOrderView->getOrderForm()->openTab('invoices'); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Invoices\Grid $grid */ + $grid = $salesOrderView->getOrderForm()->getTab('invoices')->getGridBlock(); + $filter = [ + 'order_id' => $orderId, + 'status' => $invoiceStatus, + ]; + \PHPUnit_Framework_Assert::assertTrue( + $grid->isRowVisible($filter), + 'Invoice status is incorrect.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Invoice status is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php index 6b1261892fdea..4610b86feee84 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php @@ -1,6 +1,6 @@ open(); + $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); + $salesOrderView->getPageActions()->invoice(); + + \PHPUnit_Framework_Assert::assertEquals( + self::OFFLINE_INVOICE_MESSAGE, + $orderInvoiceNew->getTotalsBlock()->getCaptureOfflineMessage(), + 'Message incorrect or is not present.' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Message that invoice can be created only offline is present."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php new file mode 100644 index 0000000000000..a6c57c563467f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php @@ -0,0 +1,62 @@ +objectManager->create( + \Magento\Customer\Test\Block\Address\Renderer::class, + ['address' => $shippingAddress, 'type' => 'html'] + )->render(); + + $selectedBillingAddress = $this->objectManager->create( + \Magento\Customer\Test\Block\Address\Renderer::class, + ['address' => $billingAddress, 'type' => 'html'] + )->render(); + + $salesOrderView->open(['order_id' => $orderId]); + $orderBillingAddress = $salesOrderView->getAddressesBlock()->getCustomerBillingAddress(); + $orderShippingAddress = $salesOrderView->getAddressesBlock()->getCustomerShippingAddress(); + + \PHPUnit_Framework_Assert::assertTrue( + $selectedBillingAddress == $orderBillingAddress && $selectedShippingAddress == $orderShippingAddress, + 'Billing and shipping addresses from the address book and from the order page are not the same.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Billing and shipping addresses from the address book and from the order page are the same.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php index 6d63e7d8896c4..ee68252924b0d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php @@ -1,6 +1,6 @@ open(); + $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); + $sendMail = isset($data['form_data']['send_email']) ? filter_var( + $data['form_data']['send_email'], + FILTER_VALIDATE_BOOLEAN + ) : false; + + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); + + \PHPUnit_Framework_Assert::assertContains( + $latestComment['is_customer_notified'], + (bool)$sendMail ? 'Customer Notified' : 'Customer Not Notified' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Message with appropriate notification status is available in Comments History section."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php index 4c30d5f68d208..68582e490eb69 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php @@ -1,34 +1,34 @@ open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); @@ -41,7 +41,7 @@ public function processAssert( } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php index 7b9af65554537..b2b7fbe06364e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php @@ -1,6 +1,6 @@ open(); + $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $actualPaymentInformation = $infoTab->getPaymentInfoBlock()->getData(); + + \PHPUnit_Framework_Assert::assertEmpty( + array_diff($paymentInfo, $actualPaymentInformation), + 'Payment Information missmatch with expected values.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Payment Information valid and matches with expected values.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php index fa45c39435906..0fe11c0ef407a 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php @@ -1,6 +1,6 @@ open(); + $grid = $salesOrder->getSalesOrderGrid(); + $grid->resetFilter(); + $grid->sortByColumn('ID'); + $grid->sortGridByField('ID'); + $grid->openFirstRow(); + + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + \PHPUnit_Framework_Assert::assertEquals( + $infoTab->getOrderStatus(), + 'Canceled' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Order status is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php index 056e97c1b6262..e96cc59547f82 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php @@ -1,6 +1,6 @@ getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); $orderStatus = $statusToCheck == null ? $status : $statusToCheck; + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); \PHPUnit_Framework_Assert::assertEquals( - $salesOrderView->getOrderForm()->getOrderInfoBlock()->getOrderStatus(), + $infoTab->getOrderStatus(), $orderStatus ); } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php index 62d36df7dd275..f89ada6992afd 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php @@ -1,6 +1,6 @@ getMessagesBlock()->getSuccessMessage(); + \PHPUnit_Framework_Assert::assertEquals( + self::SUCCESS_MESSAGE, + $actualMessage, + 'Wrong success message is displayed.' + . "\nExpected: " . self::SUCCESS_MESSAGE + . "\nActual: " . $actualMessage + ); + } + + /** + * Text of voided order message assert. + * + * @return string + */ + public function toString() + { + return 'Order successful void message is present.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrdersInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrdersInOrdersGrid.php index 20ec509fb096d..2528d9747f7df 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrdersInOrdersGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrdersInOrdersGrid.php @@ -1,6 +1,6 @@ fixtureFactory = $fixtureFactory; + parent::__construct($objectManager, $eventManager); + } + + /** + * Assert form data equals fixture data. + * + * @param OrderInjectable $order + * @param CatalogProductIndex $productGrid + * @param CatalogProductEdit $productPage + * @return void + */ + public function processAssert( + OrderInjectable $order, + CatalogProductIndex $productGrid, + CatalogProductEdit $productPage + ) { + $product = $this->getProduct($order); + $this->objectManager->get(\Magento\Catalog\Test\Constraint\AssertProductForm::class)->processAssert( + $product, + $productGrid, + $productPage + ); + } + + /** + * Get product's fixture. + * + * @param OrderInjectable $order + * @param int $index [optional] + * @return FixtureInterface + */ + protected function getProduct(OrderInjectable $order, $index = 0) + { + $product = $order->getEntityId()['products'][$index]; + $productData = $product->getData(); + $checkoutDataQty = isset($productData['checkout_data']['qty']) ? $productData['checkout_data']['qty'] : 1; + $productData['quantity_and_stock_status']['qty'] -= $checkoutDataQty; + + $productData = array_diff_key($productData, array_flip($this->skipFields)); + + return $this->fixtureFactory->create(get_class($product), ['data' => $productData]); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product qty was decreased after placing an order.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php new file mode 100644 index 0000000000000..a6b3527ac77eb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductQtyDecreasedAfterCreditmemo.php @@ -0,0 +1,110 @@ +fixtureFactory = $fixtureFactory; + parent::__construct($objectManager, $eventManager); + } + + /** + * Assert form data equals fixture data + * + * @param OrderInjectable $order + * @param array $data + * @param CatalogProductIndex $productGrid + * @param CatalogProductEdit $productPage + * @return void + */ + public function processAssert( + OrderInjectable $order, + array $data, + CatalogProductIndex $productGrid, + CatalogProductEdit $productPage + ) { + $product = $this->getProduct($order, $data); + $this->objectManager->get(\Magento\Catalog\Test\Constraint\AssertProductForm::class)->processAssert( + $product, + $productGrid, + $productPage + ); + } + + /** + * Get product's fixture. + * + * @param OrderInjectable $order + * @param array $data + * @param int $index [optional] + * @return FixtureInterface + */ + protected function getProduct(OrderInjectable $order, array $data, $index = 0) + { + if (!isset($data['items_data'][$index]['back_to_stock']) + || $data['items_data'][$index]['back_to_stock'] != 'Yes' + ) { + return $order->getEntityId()['products'][$index]; + } + $product = $order->getEntityId()['products'][$index]; + $productData = $product->getData(); + $checkoutDataQty = $productData['checkout_data']['qty']; + $productData['quantity_and_stock_status']['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']); + + $productData = array_diff_key($productData, array_flip($this->skipFields)); + + return $this->fixtureFactory->create(get_class($product), ['data' => $productData]); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product qty was decreased after creditmemo creation.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductsQtyAfterOrderCancel.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductsQtyAfterOrderCancel.php new file mode 100644 index 0000000000000..613f30fce15d6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductsQtyAfterOrderCancel.php @@ -0,0 +1,128 @@ +getEntityId()['products']); $i++) { + $product = $order->getEntityId()['products'][$i]; + $productData = $product->getData(); + if ($product instanceof BundleProduct) { + $this->assertBundleProduct($product, $productGrid, $productPage, $fixtureFactory, $assertProductForm); + } elseif ($product instanceof ConfigurableProduct) { + $assertConfigurableProductForm->processAssert( + $fixtureFactory->create( + get_class($product), + ['data' => array_diff_key($productData, array_flip($this->skipFields))] + ), + $productGrid, + $productPage + ); + } else { + $assertProductForm->processAssert( + $fixtureFactory->create( + get_class($product), + ['data' => array_diff_key($productData, array_flip($this->skipFields))] + ), + $productGrid, + $productPage + ); + } + } + } + + /** + * Assert quantity of products that are part of the bundle product. + * + * @param BundleProduct $product + * @param CatalogProductIndex $productGrid + * @param CatalogProductEdit $productPage + * @param FixtureFactory $fixtureFactory + * @param AssertProductForm $assertProductForm + * @return void + */ + public function assertBundleProduct( + BundleProduct $product, + CatalogProductIndex $productGrid, + CatalogProductEdit $productPage, + FixtureFactory $fixtureFactory, + AssertProductForm $assertProductForm + ) { + $productData = $product->getData(); + $bundleSelections = $product->getDataFieldConfig('bundle_selections')['source']->getProducts(); + foreach ($bundleSelections as $key => $selection) { + $valueName = $productData['checkout_data']['options']['bundle_options'][$key]['value']['name']; + foreach ($selection as $item) { + if (strpos($item->getName(), $valueName) !== false) { + $assertProductForm->processAssert( + $fixtureFactory->create( + get_class($product), + ['data' => array_diff_key($item->getData(), array_flip($this->skipFields))] + ), + $productGrid, + $productPage + ); + break; + } + } + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Products quantity was reverted after order cancel.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php index 9cbb7b2c9ebbb..5be581859df8f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php @@ -1,11 +1,12 @@ open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - $actualRefundedAmount = $salesOrderView->getOrderHistoryBlock()->getRefundedAmount(); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $comments = $infoTab->getCommentsHistoryBlock()->getComments(); + + foreach ($comments as $key => $comment) { + if (stristr($comment['comment'], 'refunded') === false) { + unset($comments[$key]); + } + } + $comments = array_reverse(array_values($comments)); + + $refundedPrices = $order->getPrice()['refund']; foreach ($refundedPrices as $key => $refundedPrice) { - \PHPUnit_Framework_Assert::assertContains( - self::REFUNDED_AMOUNT . $refundedPrice, - $actualRefundedAmount[$key], + \PHPUnit_Framework_Assert::assertRegExp( + sprintf(self::REFUNDED_AMOUNT_PATTERN, $refundedPrice['grand_creditmemo_total']), + $comments[$key]['comment'], 'Incorrect refunded amount value for the order #' . $orderId ); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php index f42e1de5ad13c..74862b6db45f8 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php @@ -1,6 +1,6 @@ getOrderForm()->openTab('creditmemos'); /** @var Grid $grid */ $grid = $salesOrderView->getOrderForm()->getTab('creditmemos')->getGridBlock(); - $amount = $order->getPrice(); + $amount = $order->getPrice()['refund']; foreach ($ids['creditMemoIds'] as $key => $creditMemoId) { $filter = [ 'id' => $creditMemoId, diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php index 5b63d92a17e8e..e0e13e4bf67ef 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php @@ -1,6 +1,6 @@ open(); - $amount = $order->getPrice(); + $amount = $order->getPrice()['refund']; $orderId = $order->getId(); foreach ($ids['creditMemoIds'] as $key => $creditMemoId) { $filter = [ @@ -47,7 +46,7 @@ public function processAssert(CreditMemoIndex $creditMemoIndex, OrderInjectable } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundNotInRefundsGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundNotInRefundsGrid.php new file mode 100644 index 0000000000000..2389239bef045 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundNotInRefundsGrid.php @@ -0,0 +1,57 @@ +open(); + $amount = $order->getPrice()['refund']; + $orderId = $order->getId(); + foreach ($ids['creditMemoIds'] as $key => $creditMemoId) { + $filter = [ + 'id' => $creditMemoId, + 'order_id' => $orderId, + 'grand_total_from' => $amount[$key]['grand_creditmemo_total'], + 'grand_total_to' => $amount[$key]['grand_creditmemo_total'], + ]; + $creditMemoIndex->getCreditMemoGrid()->search($filter); + $filter['grand_total_from'] = number_format($amount[$key]['grand_creditmemo_total'], 2); + $filter['grand_total_to'] = number_format($amount[$key]['grand_creditmemo_total'], 2); + \PHPUnit_Framework_Assert::assertFalse( + $creditMemoIndex->getCreditMemoGrid()->isRowVisible($filter, false, false), + "Credit memo '#$creditMemoId' is present in credit memos grid on credit memo index page." + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Credit memo is absent in credit memos grid on credit memo index page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php new file mode 100644 index 0000000000000..207c634cabdbe --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php @@ -0,0 +1,53 @@ +open(); + $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); + + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); + + \PHPUnit_Framework_Assert::assertContains( + $infoTab->getOrderStatus(), + $latestComment['status'] + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Message with appropriate order status is available in Comments History section."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php index d7df7cc8ee6c9..89626408cb555 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php @@ -1,6 +1,6 @@ getOrderViewBlock()->openLinkByName('Refunds'); foreach ($ids['creditMemoIds'] as $key => $creditMemoId) { \PHPUnit_Framework_Assert::assertEquals( - number_format($order->getPrice()[$key]['grand_creditmemo_total'], 2), + number_format($order->getPrice()['refund'][$key]['grand_creditmemo_total'], 2), $creditMemoView->getCreditMemoBlock()->getItemBlock($creditMemoId)->getGrandTotal() ); } } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php index 804c607814a3d..032c9abf62ac5 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php @@ -1,6 +1,6 @@ open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); \PHPUnit_Framework_Assert::assertEquals( $previousOrderStatus, - $salesOrderView->getOrderForm()->getOrderInfoBlock()->getOrderStatus(), + $infoTab->getOrderStatus(), 'Order status is incorrect on order page in backend.' ); } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php index 6c9bbd8eaf733..0425dd1a004b0 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php @@ -1,6 +1,6 @@ open(); + $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); + $salesOrderView->getOrderForm()->openTab('transactions'); + $actualTransactions = $salesOrderView->getOrderForm()->getTab('transactions')->getGridBlock()->getIds(); + + foreach ($transactions as $transaction) { + foreach ($actualTransactions as $actualTransaction) { + if ($actualTransaction['transactionType'] === $transaction['transactionType']) { + \PHPUnit_Framework_Assert::assertEquals( + $transaction['statusIsClosed'], + $actualTransaction['statusIsClosed'], + 'The ' . $transaction['transactionType'] . ' transaction status is not closed.' + ); + break; + } + } + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Transactions status is closed.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php index 3abbf92ca2885..e2758ec54a99e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php @@ -1,6 +1,6 @@ open(); + $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); + + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ + $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); + $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); + + \PHPUnit_Framework_Assert::assertContains( + self::VOIDED_AMOUNT . $prices['grandTotal'], + $latestComment['comment'], + 'Incorrect voided amount value for the order #' . $orderId + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Message about voided amount is available in Comments History section."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable.xml index 115ec14741aba..2abd9f70bcfd9 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable.xml @@ -1,7 +1,7 @@ @@ -206,5 +206,6 @@ + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable/BillingAddressId.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable/BillingAddressId.php index 59f34ed875fc3..7e879b4163c98 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable/BillingAddressId.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderInjectable/BillingAddressId.php @@ -1,6 +1,6 @@ params = $params; - $storeData = isset($data['dataset']) ? ['dataset' => $data['dataset']] : []; if (isset($data['data'])) { $storeData = array_replace_recursive($storeData, $data); } - if ($storeData) { - $store = $fixtureFactory->createByCode('store', $storeData); - /** @var Store $store */ - if (!$store->getStoreId()) { - $store->persist(); + if (isset($data['store'])) { + $this->store = $data['store']; + $website = $data['store']->getDataFieldConfig('group_id')['source'] + ->getStoreGroup()->getDataFieldConfig('website_id')['source']->getWebsite(); + $this->website = $website; + $this->data = $data['store']->getName(); + } else { + if ($storeData) { + $store = $fixtureFactory->createByCode('store', $storeData); + /** @var Store $store */ + if (!$store->getStoreId()) { + $store->persist(); + } + if (isset($store->getData()['group_id'])) { + $website = $store->getDataFieldConfig('group_id')['source'] + ->getStoreGroup()->getDataFieldConfig('website_id')['source']->getWebsite(); + $this->website = $website; + } + + $this->store = $store; + $this->data = $store->getName(); } - $this->store = $store; - $this->data = $store->getName(); } } @@ -57,4 +78,17 @@ public function getStore() { return $this->store; } + + /** + * Return Website fixture. + * + * @return Website|null + */ + public function getWebsite() + { + if (isset($this->website)) { + return $this->website; + } + return null; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderStatus.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderStatus.xml index 06a2104aa1813..3866c069ef149 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderStatus.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Fixture/OrderStatus.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Curl.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Curl.php index 5b780a709d126..0d3769a0c0e65 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Curl.php @@ -1,6 +1,6 @@ createQuote($fixture); - $url = $this->isCustomerGuest ? 'guest-carts/' . $this->quote : 'carts/' . (int)$this->quote; - $this->url = $_ENV['app_frontend_url'] . 'rest/V1/' . $url; + $this->url = $_ENV['app_frontend_url'] . $this->prepareWebsiteUrl($fixture) . '/V1/' . $url; $this->setProducts($fixture); $this->setCoupon($fixture); @@ -78,8 +77,9 @@ public function persist(FixtureInterface $fixture = null) $this->setShippingInformation($fixture); $this->setPaymentMethod($fixture); $orderId = $this->placeOrder(); + $orderIncrementId = $this->getOrderIncrementId($orderId); - return ['id' => sprintf("%09d", $orderId)]; + return ['id' => $orderIncrementId]; } /** @@ -92,7 +92,7 @@ public function persist(FixtureInterface $fixture = null) protected function createQuote(OrderInjectable $order) { if ($this->isCustomerGuest) { - $url = $_ENV['app_frontend_url'] . 'rest/V1/guest-carts'; + $url = $_ENV['app_frontend_url'] . $this->prepareWebsiteUrl($order) . '/V1/guest-carts'; $this->webapiTransport->write($url); $response = json_decode($this->webapiTransport->read(), true); $this->webapiTransport->close(); @@ -102,7 +102,8 @@ protected function createQuote(OrderInjectable $order) } $this->quote = $response; } else { - $url = $_ENV['app_frontend_url'] . 'rest/V1/customers/' . $order->getCustomerId()->getId() . '/carts'; + $url = $_ENV['app_frontend_url'] . $this->prepareWebsiteUrl($order) + . '/V1/customers/' . $order->getCustomerId()->getId() . '/carts'; $data = '{"customerId": "' . $order->getCustomerId()->getId() . '"}'; $this->webapiTransport->write($url, $data); $response = json_decode($this->webapiTransport->read(), true); @@ -357,4 +358,41 @@ protected function prepareDownloadableOptions(DownloadableProduct $product) return ['extension_attributes' => ['downloadable_option' => ['downloadable_links' => $links]]]; } + + /** + * Prepare url for placing order in custom website. + * + * @param OrderInjectable $order + * @return string + */ + private function prepareWebsiteUrl(OrderInjectable $order) + { + $url = 'rest'; + if ($website = $order->getDataFieldConfig('store_id')['source']->getWebsite()) { + $store = $order->getDataFieldConfig('store_id')['source']->getStore(); + $url = 'websites/' . $website->getCode() . '/rest/' . $store->getCode(); + } + return $url; + } + + /** + * Retrieve order increment id. + * + * @param int $orderId + * @return string + * @throws \Exception + */ + private function getOrderIncrementId($orderId) + { + $url = $_ENV['app_frontend_url'] . 'rest/V1/orders/' . $orderId; + $this->webapiTransport->write($url, [], WebapiDecorator::GET); + $response = json_decode($this->webapiTransport->read(), true); + $this->webapiTransport->close(); + + if (!$response['increment_id']) { + $this->eventManager->dispatchEvent(['webapi_failed'], [$response]); + throw new \Exception('Could not get order details using web API.'); + } + return $response['increment_id']; + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderStatus/Curl.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderStatus/Curl.php index 0cf4e8e3d214e..473038555ab52 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderStatus/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderStatus/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/InvoiceIndex.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/InvoiceIndex.xml index 6b6bcf1b761a8..bedfa8b817e70 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/InvoiceIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/InvoiceIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreateIndex.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreateIndex.xml index f80715543de67..e43f6b0181bc9 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreateIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreateIndex.xml @@ -1,7 +1,7 @@ @@ -14,5 +14,7 @@ + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreditMemoNew.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreditMemoNew.xml index a47486e823f08..8eb5c00b3ddda 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreditMemoNew.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderCreditMemoNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderIndex.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderIndex.xml index 1382f1c2567dd..6fb934490747d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderIndex.xml @@ -1,14 +1,14 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceNew.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceNew.xml index 4c26c13442ece..6d30ab4af1a79 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceNew.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceView.xml index e6c5106642567..769023a664cf0 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderInvoiceView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusAssign.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusAssign.xml index d39ff83ca7f1d..5261416fcdcff 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusAssign.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusAssign.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusEdit.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusEdit.xml index 1bca74d31c896..6de74daceebef 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusEdit.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusEdit.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusIndex.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusIndex.xml index ef856f848076a..42f9846a27a70 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusNew.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusNew.xml index ac51d8935ef26..6f3223d054e2d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusNew.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/OrderStatusNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesCreditMemoView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesCreditMemoView.xml index f84a0e70e28ac..2997bb0d1c8f2 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesCreditMemoView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesCreditMemoView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesInvoiceView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesInvoiceView.xml index 01a76b5e61ae6..b0824605c837f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesInvoiceView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesInvoiceView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesOrderView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesOrderView.xml index d5b7d99661806..6d1aceb70bf4f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesOrderView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/Adminhtml/SalesOrderView.xml @@ -1,7 +1,7 @@ @@ -13,8 +13,9 @@ - + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CreditMemoView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CreditMemoView.xml index ec98a8470178f..1b4a9aa5ec977 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CreditMemoView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CreditMemoView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CustomerOrderView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CustomerOrderView.xml index 035c58386a27a..defa2ed1fb0ad 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CustomerOrderView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/CustomerOrderView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/InvoiceView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/InvoiceView.xml index 791a8deda4dc7..929ffaf3a577c 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/InvoiceView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/InvoiceView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/OrderHistory.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/OrderHistory.xml index b3649f7035be6..5b5e3781eb29f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/OrderHistory.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/OrderHistory.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestForm.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestForm.xml index c461915a8514d..4fb8e76e3ac95 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestForm.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestForm.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestPrint.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestPrint.xml index 8fed4342f757f..be03b652df695 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestPrint.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestPrint.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestView.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestView.xml index dae790c8775aa..6c874d039cbec 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestView.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesGuestView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesOrderShipmentNew.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesOrderShipmentNew.php index 8dde4d6b1115e..ac8634ea769bb 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesOrderShipmentNew.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Page/SalesOrderShipmentNew.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml index 65335ced8ed4c..bdc1b88eea127 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml @@ -1,7 +1,7 @@ @@ -251,5 +251,32 @@ 0 USD + + + + catalogProductSimple::default + + + default + + + US_address + + + custom_store + + flatrate_flatrate + + checkmo + + + free + + 0 + USD + + full_flow + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable/Price.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable/Price.xml index 3e2dfdd712507..394100f044fff 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable/Price.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable/Price.xml @@ -1,7 +1,7 @@ @@ -19,6 +19,13 @@ + + + 15 + 15 + + + 210 @@ -27,20 +34,52 @@ - - 565 + + + 565 + - - 555 + + + 555 + + + + + 110 + + + + + - 110 + 0 + 0 + + + + + + 5 + + + + + + + 565 + + + + 565 + 565 diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderStatus.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderStatus.xml index a2b419b684c19..661e21f44260e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderStatus.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderStatus.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/AssignCustomOrderStatusTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/AssignCustomOrderStatusTest.php index 6d49174e069a6..34d29cfc01299 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/AssignCustomOrderStatusTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/AssignCustomOrderStatusTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.php index 1779ad437c76e..0c9dfe4bf92fd 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.php @@ -1,6 +1,6 @@ objectManager->create( - \Magento\Config\Test\TestStep\SetupConfigurationStep::class, - ['configData' => 'checkmo, flatrate', 'rollback' => true] - )->run(); - } + private $configData; /** - * Inject pages + * Inject pages. * * @param OrderIndex $orderIndex * @param SalesOrderView $salesOrderView @@ -77,11 +72,18 @@ public function __inject(OrderIndex $orderIndex, SalesOrderView $salesOrderView) * Cancel created order. * * @param OrderInjectable $order + * @param TestStepFactory $stepFactory + * @param string $configData * @return array */ - public function test(OrderInjectable $order) + public function test(OrderInjectable $order, TestStepFactory $stepFactory, $configData) { // Preconditions + $this->configData = $configData; + $stepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); $order->persist(); // Steps @@ -93,4 +95,17 @@ public function test(OrderInjectable $order) 'customer' => $order->getDataFieldConfig('customer_id')['source']->getCustomer(), ]; } + + /** + * Reset config settings to default. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml index bcacacc57589a..8dabeb833d390 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml @@ -1,20 +1,64 @@ - - cancel order and check status on storefront + default - catalogProductSimple::default,catalogProductSimple::default + catalogProductSimple::low_stock_product,catalogProductVirtual::virtual_low_stock,bundleProduct::bundle_low_stock,configurableProduct::configurable_low_stock Canceled + checkmo + + + stable:no + default + free + freeshipping_freeshipping + active_sales_rule_with_fixed_price_discount_coupon + catalogProductSimple::product_10_dollar + Canceled + zero_subtotal_checkout, freeshipping + + + + + default + banktransfer + Canceled + banktransfer + + + + + default + cashondelivery + Canceled + cashondelivery + + + + + default + purchaseorder + Canceled + purchaseorder + + + + + default + catalogProductSimple::low_stock_product + decrease_stock_after_order_no + + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CloseOrderTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CloseOrderTest.php new file mode 100644 index 0000000000000..a6b3a50c9fb7c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CloseOrderTest.php @@ -0,0 +1,45 @@ + Orders page. + * 3. Open order. + * 4. Click 'Ship' button and submit shipment. + * 5. Click 'Invoice' button. + * 6. Select Amount=Capture Online. + * 7. Click 'Submit Invoice' button. + * 8. Perform assertions. + * + * @group Order_Management + * @ZephyrId MAGETWO-13015, MAGETWO-13020 + */ +class CloseOrderTest extends Scenario +{ + /* tags */ + const MVP = 'yes'; + const TEST_TYPE = '3rd_party_test'; + const SEVERITY = 'S0'; + /* end tags */ + + /** + * Close order. + * + * @return void + */ + public function test() + { + $this->executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php index ed00a414bd0e6..8f8c69a9f492e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.php @@ -1,6 +1,6 @@ fixtureFactory = $fixtureFactory; - - $setupConfigurationStep = $this->objectManager->create( - \Magento\Config\Test\TestStep\SetupConfigurationStep::class, - ['configData' => 'checkmo, flatrate'] - ); - $setupConfigurationStep->run(); - } - /** * Create credit memo. * + * @param TestStepFactory $stepFactory + * @param FixtureFactory $fixtureFactory * @param OrderInjectable $order * @param array $data + * @param string|null $configData [optional] * @return array */ - public function test(OrderInjectable $order, array $data) - { + public function test( + TestStepFactory $stepFactory, + FixtureFactory $fixtureFactory, + OrderInjectable $order, + array $data, + $configData = null + ) { // Preconditions + $this->fixtureFactory = $fixtureFactory; + $stepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); $order->persist(); - $this->objectManager->create(\Magento\Sales\Test\TestStep\CreateInvoiceStep::class, ['order' => $order])->run(); + $stepFactory->create(\Magento\Sales\Test\TestStep\CreateInvoiceStep::class, ['order' => $order])->run(); // Steps - $createCreditMemoStep = $this->objectManager->create( + $createCreditMemoStep = $stepFactory->create( \Magento\Sales\Test\TestStep\CreateCreditMemoStep::class, ['order' => $order, 'data' => $data] ); @@ -93,32 +90,7 @@ public function test(OrderInjectable $order, array $data) return [ 'ids' => ['creditMemoIds' => $result['creditMemoIds']], - 'product' => $this->getProduct($order, $data), 'customer' => $order->getDataFieldConfig('customer_id')['source']->getCustomer() ]; } - - /** - * Get product's fixture. - * - * @param OrderInjectable $order - * @param array $data - * @param int $index [optional] - * @return FixtureInterface - */ - protected function getProduct(OrderInjectable $order, array $data, $index = 0) - { - if (!isset($data['items_data'][$index]['back_to_stock']) - || $data['items_data'][$index]['back_to_stock'] != 'Yes' - ) { - return $order->getEntityId()['products'][$index]; - } - $product = $order->getEntityId()['products'][$index]; - $productData = $product->getData(); - $checkoutDataQty = $productData['checkout_data']['qty']; - $productData['quantity_and_stock_status']['qty'] -= ($checkoutDataQty - $data['items_data'][$index]['qty']); - $productData = array_diff_key($productData, array_flip($this->skipFields)); - - return $this->fixtureFactory->create(get_class($product), ['data' => $productData]); - } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml index 40f5c0aefc60a..8d67f23a9286e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCreditMemoEntityTest.xml @@ -1,36 +1,39 @@ - - Assert items return to stock (partial refund) + Yes 1 + Yes default catalogProductSimple::product_100_dollar partial_refund + checkmo + + - + - - Assert 0 shipping refund + 1 0 5 10 default - catalogProductSimple::default + banktransfer full_refund_with_zero_shipping_refund + banktransfer @@ -38,5 +41,29 @@ + + 1 + 0 + 5 + 10 + default + cashondelivery + full_refund_with_zero_shipping_refund + cashondelivery + + + + + 1 + 0 + 5 + 10 + default + purchaseorder + full_refund_with_zero_shipping_refund + purchaseorder + + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCustomOrderStatusEntityTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCustomOrderStatusEntityTest.php index 3dc689a385271..482a430fdbec5 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCustomOrderStatusEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateCustomOrderStatusEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.php index f62583583c3dc..bbfcb768a5227 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.php @@ -1,6 +1,6 @@ objectManager->create( - \Magento\Config\Test\TestStep\SetupConfigurationStep::class, - ['configData' => 'checkmo, flatrate'] - )->run(); + $this->stepFactory = $stepFactory; } /** @@ -50,15 +57,20 @@ public function __prepare() * * @param OrderInjectable $order * @param array $data + * @param string $configData * @return array */ - public function test(OrderInjectable $order, array $data) + public function test(OrderInjectable $order, array $data, $configData) { // Preconditions + $this->stepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); $order->persist(); // Steps - $result = $this->objectManager->create( + $result = $this->stepFactory->create( \Magento\Sales\Test\TestStep\CreateInvoiceStep::class, ['order' => $order, 'data' => $data] )->run(); @@ -73,6 +85,6 @@ public function test(OrderInjectable $order, array $data) */ public function tearDown() { - $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); + $this->stepFactory->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.xml index afc4bad5e706d..e52aa37251312 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateInvoiceEntityTest.xml @@ -1,7 +1,7 @@ @@ -10,11 +10,11 @@ default full_invoice - catalogProductSimple::default 1 - Yes comments + checkmo @@ -29,14 +29,57 @@ partial_invoice catalogProductSimple::product_100_dollar - + banktransfer 1 No comments + banktransfer + + default + partial_invoice + catalogProductSimple::product_100_dollar + - + cashondelivery + 1 + No + comments + cashondelivery + + + + + default + partial_invoice + catalogProductSimple::product_100_dollar + - + purchaseorder + 1 + No + comments + purchaseorder + + + + + default + free_invoice + catalogProductSimple::product_10_dollar + - + free + freeshipping_freeshipping + active_sales_rule_with_fixed_price_discount_coupon + 1 + No + comments + zero_subtotal_checkout, freeshipping + + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOnlineCreditMemoTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOnlineCreditMemoTest.php new file mode 100644 index 0000000000000..e3cb9146f5c43 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOnlineCreditMemoTest.php @@ -0,0 +1,41 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOnlineInvoiceEntityTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOnlineInvoiceEntityTest.php index c3b00b4b7f794..99a0fefa2c385 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOnlineInvoiceEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOnlineInvoiceEntityTest.php @@ -1,6 +1,6 @@ - + Create order with simple product for registered US customer using Fixed shipping method and Cash on Delivery payment method - catalogProductSimple::default + catalogProductSimple::with_one_custom_option default US_address_1_without_email No Flat Rate Fixed - 565.00 + 425.00 cashondelivery Pending @@ -27,6 +27,7 @@ + Create order with virtual product for registered UK customer using Check/Money Order payment method @@ -69,6 +70,7 @@ + to_maintain:yes Create order with virtual product for registered UK customer using Bank Transfer payment method catalogProductVirtual::default default @@ -147,5 +149,21 @@ + + catalogProductSimple::product_with_qty_25 + default + US_address_1_without_email + No + Flat Rate + Fixed + + 375.00 + + cashondelivery + cashondelivery + + + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFilteringTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFilteringTest.xml index 4e61abb7c5d50..394526d6e4cb1 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFilteringTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFilteringTest.xml @@ -1,13 +1,15 @@ + severity:S2 + stable:no Verify sales order grid filtering - @@ -32,6 +34,7 @@ + severity:S3 Verify sales invoice grid filtering Magento\Sales\Test\TestStep\CreateInvoiceStep @@ -55,6 +58,7 @@ + severity:S3 Verify sales shipment grid filtering Magento\Sales\Test\TestStep\CreateShipmentStep @@ -78,6 +82,7 @@ + severity:S3 Verify sales credit memo grid filtering diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFullTextSearchTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFullTextSearchTest.xml index abd9432fe098e..91dc7748eaee7 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFullTextSearchTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridFullTextSearchTest.xml @@ -1,13 +1,14 @@ + severity:S2, stable:no Verify sales order grid full text search - @@ -23,6 +24,7 @@ + severity:S3, stable:no Verify sales invoice grid full text search Magento\Sales\Test\TestStep\CreateInvoiceStep @@ -39,6 +41,7 @@ + severity:S3 Verify sales shipment grid full text search Magento\Sales\Test\TestStep\CreateShipmentStep @@ -55,6 +58,7 @@ + severity:S3, stable:no Verify sales credit memo grid full text search diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridSortingTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridSortingTest.xml index 056fa5136d433..7874fc0c4a361 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridSortingTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/GridSortingTest.xml @@ -1,13 +1,15 @@ + severity:S2 + to_maintain:yes Verify sales order grid storting - @@ -26,6 +28,8 @@ + severity:S3 + to_maintain:yes Verify sales invoince grid storting Magento\Sales\Test\TestStep\CreateInvoiceStep @@ -43,6 +47,8 @@ + severity:S3 + to_maintain:yes Verify sales shipment grid storting Magento\Sales\Test\TestStep\CreateShipmentStep @@ -60,6 +66,8 @@ + severity:S3 + to_maintain:yes Verify sales credit memo grid storting diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/HoldCreatedOrderTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/HoldCreatedOrderTest.php index 8b45a8a22eecf..9344e4e2b4f7a 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/HoldCreatedOrderTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/HoldCreatedOrderTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.php index 4f62fa07bba42..d31b5aa9eb947 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.php @@ -1,6 +1,6 @@ + stable:no cancel orders in status Pending and Processing - Cancel @@ -44,6 +45,7 @@ + stable:no Try to put order in status Complete on Hold invoice, shipment Hold diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveLastOrderedProductsOnOrderPageTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveLastOrderedProductsOnOrderPageTest.php index 719ae58630513..fbbd92c87f18d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveLastOrderedProductsOnOrderPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveLastOrderedProductsOnOrderPageTest.php @@ -1,6 +1,6 @@ + stable:no default catalogProductSimple::default + MAGETWO-58762: Customer grid does not open in MoveLastOrderedProductsOnOrderPageTestVariation2 on Jenkins default configurableProduct::configurable_with_qty_1 diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveProductsInComparedOnOrderPageTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveProductsInComparedOnOrderPageTest.php index cedf2aeb71c58..c4f2f51ac36ae 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveProductsInComparedOnOrderPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveProductsInComparedOnOrderPageTest.php @@ -1,6 +1,6 @@ + to_maintain:yes catalogProductSimple::default catalogProductSimple::default + to_maintain:yes configurableProduct::configurable_with_qty_1 configurableProduct::configurable_with_qty_1 diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php index 49487ff1b2e8e..dd32ed25a45de 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.php @@ -1,6 +1,6 @@ getRecentlyComparedProductsBlock()->addProductsToOrder($products); $activitiesBlock->updateChanges(); - return ['products' => $products, 'productsIsConfigured' => false]; + return ['products' => $products, 'productsIsConfigured' => $productsIsConfigured]; } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml index e6f96da0367ca..6c513c75b3dbb 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyComparedProductsOnOrderPageTest.xml @@ -1,21 +1,16 @@ - + catalogProductSimple::default catalogProductSimple::default - - configurableProduct::configurable_with_qty_1 - configurableProduct::configurable_with_qty_1 - - diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyViewedProductsOnOrderPageTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyViewedProductsOnOrderPageTest.php index d6a4b685e5711..c601e80c9e301 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyViewedProductsOnOrderPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveRecentlyViewedProductsOnOrderPageTest.php @@ -1,6 +1,6 @@ + to_maintain:yes configurableProduct::default + to_maintain:yes bundleProduct::bundle_fixed_product diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php index 21a13d782e0d5..90f98d1d84fb8 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MoveShoppingCartProductsOnOrderPageTest.php @@ -1,6 +1,6 @@ + stable:no catalogProductSimple::default + stable:no configurableProduct::configurable_with_qty_1 diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml index f7a6ab637541a..c0f37ffaa4cb2 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/PrintOrderFrontendGuestTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/PrintOrderFrontendGuestTest.php index 4e05d4025fce4..676220eec2cfb 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/PrintOrderFrontendGuestTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/PrintOrderFrontendGuestTest.php @@ -1,6 +1,6 @@ + to_maintain:yes johndoe_with_addresses diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/ReorderOrderEntityTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/ReorderOrderEntityTest.php index 60547dd9e03e1..fd75b31ff53db 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/ReorderOrderEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/ReorderOrderEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes Reorder placed order (update products, billing address). two_simple_product active_sales_rule_with_fixed_price_discount_coupon diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UnassignCustomOrderStatusTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UnassignCustomOrderStatusTest.php index de9939ce106ad..5e6496d54f7f8 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UnassignCustomOrderStatusTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UnassignCustomOrderStatusTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UpdateCustomOrderStatusTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UpdateCustomOrderStatusTest.php index e5da53b48b74e..8bada905eca28 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UpdateCustomOrderStatusTest.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/UpdateCustomOrderStatusTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/VoidAuthorizationTest.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/VoidAuthorizationTest.php new file mode 100644 index 0000000000000..bc368baea3308 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/VoidAuthorizationTest.php @@ -0,0 +1,50 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php index 594f7098e4559..2cf60f85ea474 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddProductsStep.php @@ -1,49 +1,60 @@ orderCreateIndex = $orderCreateIndex; $this->products = $products; + $this->fixtureFactory = $fixtureFactory; } /** - * Add product to sales + * Add product to sales. * - * @return void + * @return array */ public function run() { @@ -58,5 +69,8 @@ public function run() } $createBlock->addSelectedProductsToOrder(); $createBlock->getTemplateBlock()->waitLoader(); + + $cart['data']['items'] = ['products' => $this->products]; + return ['cart' => $this->fixtureFactory->createByCode('cart', $cart)]; } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddRecentlyViewedProductsToCartStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddRecentlyViewedProductsToCartStep.php index 533ac3fe097ed..2f4d0664412ec 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddRecentlyViewedProductsToCartStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/AddRecentlyViewedProductsToCartStep.php @@ -1,6 +1,6 @@ cart = $cart; $this->orderIndex = $orderIndex; $this->salesOrderView = $salesOrderView; $this->order = $order; + $this->orderInvoiceView = $orderInvoiceView; $this->orderCreditMemoNew = $orderCreditMemoNew; $this->refundData = $refundData; - $this->orderInvoiceView = $orderInvoiceView; } /** @@ -95,19 +104,20 @@ public function run() { $this->orderIndex->open(); $this->orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $this->order->getId()]); - /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Invoices\Grid $invoicesGrid */ - $invoicesGrid = $this->salesOrderView->getOrderForm()->getTab('invoices')->getGridBlock(); - $this->salesOrderView->getOrderForm()->openTab('invoices'); - $invoicesGrid->viewInvoice(); - $this->salesOrderView->getPageActions()->orderInvoiceCreditMemo(); - if (!empty($this->refundData)) { + $refundsData = $this->order->getRefund(); + foreach ($refundsData as $refundData) { + /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Invoices\Grid $invoicesGrid */ + $invoicesGrid = $this->salesOrderView->getOrderForm()->getTab('invoices')->getGridBlock(); + $this->salesOrderView->getOrderForm()->openTab('invoices'); + $invoicesGrid->viewInvoice(); + $this->salesOrderView->getPageActions()->orderInvoiceCreditMemo(); $this->orderCreditMemoNew->getFormBlock()->fillProductData( - $this->refundData, - $this->order->getEntityId()['products'] + $refundData, + $this->cart->getItems() ); $this->orderCreditMemoNew->getFormBlock()->updateQty(); + $this->orderCreditMemoNew->getFormBlock()->submit(); } - $this->orderCreditMemoNew->getFormBlock()->submit(); return ['ids' => ['creditMemoIds' => $this->getCreditMemoIds()]]; } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/CreateOrderStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/CreateOrderStep.php index df6e9766e3a1b..89f2124b92ff4 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/CreateOrderStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/CreateOrderStep.php @@ -1,6 +1,6 @@ salesOrderView->getOrderForm()->openTab('shipments'); - return $this->salesOrderView->getOrderForm()->getTab('shipments')->getGridBlock()->getIds(); + $this->salesOrderView->getOrderForm()->getTab('shipments')->getGridBlock()->resetFilter(); + $shipmentIds = $this->salesOrderView->getOrderForm()->getTab('shipments')->getGridBlock()->getAllIds(); + $incrementIds = []; + foreach ($shipmentIds as $shipmentId) { + $incrementIds[] = $this->salesOrderView->getOrderForm() + ->getTab('shipments') + ->getGridBlock() + ->getColumnValue($shipmentId, self::COLUMN_NAME); + } + return $incrementIds; } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/FillAccountInformationStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/FillAccountInformationStep.php index 88859393c92b4..b678d13683bee 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/FillAccountInformationStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/FillAccountInformationStep.php @@ -1,6 +1,6 @@ orderCreateIndex = $orderCreateIndex; $this->billingAddress = $billingAddress; + $this->shippingAddress = $shippingAddress; $this->saveAddress = $saveAddress; $this->setShippingAddress = $setShippingAddress; } /** - * Fill Sales Data. + * Fill Billing Address. * - * @return Address + * @return array */ public function run() { + if ($this->shippingAddress !== null) { + $this->setShippingAddress = null; + } $this->orderCreateIndex->getCreateBlock() - ->fillAddresses($this->billingAddress, $this->saveAddress, $this->setShippingAddress); + ->fillBillingAddress($this->billingAddress, $this->saveAddress, $this->setShippingAddress); return ['billingAddress' => $this->billingAddress]; } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/FillShippingAddressStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/FillShippingAddressStep.php new file mode 100644 index 0000000000000..b52ad15849321 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/FillShippingAddressStep.php @@ -0,0 +1,55 @@ +orderCreateIndex = $orderCreateIndex; + $this->shippingAddress = $shippingAddress; + } + + /** + * Fill Shipping Address. + * + * @return void + */ + public function run() + { + if ($this->shippingAddress !== null) { + $this->orderCreateIndex->getCreateBlock()->fillShippingAddress($this->shippingAddress); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/OnHoldStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/OnHoldStep.php index fe110ec8c7e8f..87d034899a536 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/OnHoldStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/OnHoldStep.php @@ -1,6 +1,6 @@ orderCreateIndex = $orderCreateIndex; $this->payment = $payment; - if (isset($creditCard['dataset'])) { - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); - } + $this->creditCard = $creditCard; } /** - * Fill Payment data + * Fill Payment data. * * @return void */ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectShippingMethodForOrderStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectShippingMethodForOrderStep.php index c4314c4c80b38..08d6ed14e4dc4 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectShippingMethodForOrderStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SelectShippingMethodForOrderStep.php @@ -1,6 +1,6 @@ orderCreateIndex = $orderCreateIndex; + } + + /** + * Fill Sales Data. + * + * @return void + */ + public function run() + { + $this->orderCreateIndex->getCreateBlock()->submitOrder(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SubmitOrderStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SubmitOrderStep.php index fa37c94be3cdd..4688fb9778738 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SubmitOrderStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/SubmitOrderStep.php @@ -1,6 +1,6 @@ orderCreateIndex = $orderCreateIndex; $this->salesOrderView = $salesOrderView; diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/UpdateProductsDataStep.php b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/UpdateProductsDataStep.php index 2f48bfbf781f8..c0213788d947c 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/UpdateProductsDataStep.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestStep/UpdateProductsDataStep.php @@ -1,6 +1,6 @@ orderIndex = $orderIndex; + $this->order = $order; + $this->salesOrderView = $salesOrderView; + } + + /** + * Void authorization. + * + * @return void + */ + public function run() + { + $this->orderIndex->open(); + $this->orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $this->order->getId()]); + $this->salesOrderView->getPageActions()->void(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/curl/di.xml index 49c0fd0ed7852..88c6f43157c79 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml index ea687be19d3c3..d77d737a2e9f9 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml @@ -1,39 +1,114 @@ - high + S0 + + + + + S1 - high + S0 - high + S0 - high + S0 - high + S0 + + + + + S0 - high + S0 + + + + + S0 + + + + + S0 + + + + + S0 + + + + + S0 + + + + + S0 + + + + + S0 + + + + + S1 + + + + + S2 + + + + + S0 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S0 diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/testcase.xml index c48430b00e7ea..531d8f61a6c7d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/testcase.xml @@ -1,7 +1,7 @@ @@ -11,7 +11,8 @@ - + + @@ -28,11 +29,28 @@ - + + + + + + + + + + + + + + + + + + @@ -41,7 +59,8 @@ - + + @@ -60,10 +79,40 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/webapi/di.xml index aa66f67bba3d3..a5facebde3626 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Grid.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Grid.php index 4ff89158c0906..f419c1feb72b3 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Grid.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Grid.php @@ -1,6 +1,6 @@ @@ -40,8 +40,8 @@ \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::div[@class='rule-tree']] - xpath + [data-index="conditions"] + css selector .fieldset[id^="sales_rule_formrule_conditions_fieldset_"] @@ -51,8 +51,8 @@ \Magento\Ui\Test\Block\Adminhtml\Section - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::select[@name='simple_action']] - xpath + [data-index="actions"] + css selector select @@ -77,7 +77,7 @@ \Magento\SalesRule\Test\Block\Adminhtml\Promo\Quote\Edit\Section\Labels - //div[contains(@class,'admin__collapsible-block-wrapper')][descendant::input[@name='store_labels[0]']] - xpath + [data-index="labels"] + css selector diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/Conditions.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/Conditions.php index 23c7a5bc62d80..1c11128712a35 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/Conditions.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/Conditions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Fixture/SalesRule/ConditionsSerialized.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Fixture/SalesRule/ConditionsSerialized.php index cb2fedc6c8716..f960758f70861 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Fixture/SalesRule/ConditionsSerialized.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Fixture/SalesRule/ConditionsSerialized.php @@ -1,6 +1,6 @@ \Magento\SalesRule\Model\Rule\Condition\Address::class, 'attribute' => 'postcode', ], + 'Total Weight' => [ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Address::class, + 'attribute' => 'weight', + ], 'Category' => [ 'type' => \Magento\SalesRule\Model\Rule\Condition\Product::class, 'attribute' => 'category_ids', diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/SalesRuleInterface.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/SalesRuleInterface.php index 666f60a937eda..d94f337497110 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/SalesRuleInterface.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Handler/SalesRule/SalesRuleInterface.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteIndex.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteIndex.xml index fc543b9b57f5f..70a353738772a 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteIndex.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteNew.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteNew.xml index e3b87416d62b5..20a6a82bc97cd 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteNew.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/Adminhtml/PromoQuoteNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/SalesGuestPrint.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/SalesGuestPrint.xml index 083022d03f558..6381582d8f659 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/SalesGuestPrint.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Page/SalesGuestPrint.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml index 010b9d3233d16..911ac8e8482bb 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml @@ -1,7 +1,7 @@ @@ -114,10 +114,10 @@ 13 63 - 3/25/2014 + 03/25/2014 - 6/29/2024 + - 1 Yes @@ -279,5 +279,24 @@ No No + + Cart price rule with free shipping by weight + Yes + + Main Website + + + NOT LOGGED IN + + No Coupon + 1 + Yes + [Total Weight|is|1] + Percent of product price discount + 0 + No + No + For matching items only + diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ApplySeveralSalesRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ApplySeveralSalesRuleEntityTest.php index a5a554f7a180b..f70cfbf33f7fc 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ApplySeveralSalesRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ApplySeveralSalesRuleEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes active_sales_rule_product_subselection active_sales_rule_product_attribute 200.00 @@ -31,6 +32,7 @@ + stable:no active_sales_rule_product_attribute active_sales_total_items 250.00 @@ -43,6 +45,7 @@ + to_maintain:yes active_sales_rule_row_total active_sales_total_items simple_for_salesrule_1 diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php index a07799d5f1ed7..68f4470dc275c 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php @@ -1,6 +1,6 @@ @@ -145,6 +145,7 @@ + stable:no United States California 95814 @@ -398,5 +399,30 @@ + + Cart Price Rule1 %isolation% + Cart Price Rule Description %isolation% + Yes + Main Website + NOT LOGGED IN + No Coupon + Percent of product price discount + [Subtotal|greater than|0] + 50 + No + For matching items only + Sales Cart Rule labels + 100.00 + 50.00 + 50.00 + United States + California + 95814 + simple_for_salesrule_1 + 1 + + + + diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.php index 7e0204a90d4e1..405c2cccbcee4 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.php @@ -1,6 +1,6 @@ persist(); + if ($productForSalesRule1) { + $productForSalesRule1->persist(); + } + // Steps $this->promoQuoteIndex->open(); $this->promoQuoteIndex->getPromoQuoteGrid()->searchAndOpen(['name' => $salesRule->getName()]); diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.xml index 80dafe5b30181..f0aeed9302691 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/DeleteSalesRuleEntityTest.xml @@ -1,7 +1,7 @@ @@ -17,10 +17,13 @@ - + inactive_sales_rule + simple_for_salesrule_1 + 1 + diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml index 32fe49d162f81..7ed8502e8f78b 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/OnePageCheckoutWithDiscountTest.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/OnePageCheckoutWithDiscountTest.php index 95fae4642d878..9e0687689866b 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/OnePageCheckoutWithDiscountTest.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/OnePageCheckoutWithDiscountTest.php @@ -1,6 +1,6 @@ testStepFactory = $testStepFactory; + } + + /** + * Test sales rule with free shipping applied by product weight + * + * @param \Magento\SalesRule\Test\Fixture\SalesRule $salesRule + * @param \Magento\Catalog\Test\Fixture\CatalogProductSimple $product + * @param \Magento\Checkout\Test\Fixture\Cart $cart + * @return void + */ + public function testRuleWithFreeShippingByWeight( + \Magento\SalesRule\Test\Fixture\SalesRule $salesRule, + \Magento\Catalog\Test\Fixture\CatalogProductSimple $product, + \Magento\Checkout\Test\Fixture\Cart $cart + ) { + $salesRule->persist(); + $product->persist(); + + $this->testStepFactory->create( + \Magento\Checkout\Test\TestStep\AddProductsToTheCartStep::class, + ['products' => [$product]] + )->run(); + + $this->testStepFactory->create( + \Magento\Checkout\Test\TestStep\EstimateShippingAndTaxStep::class, + ['products' => [$product], 'cart' => $cart] + )->run(); + } + + /** + * Clear data after test. + * + * @return void + */ + public function tearDown() + { + $this->testStepFactory->create(\Magento\SalesRule\Test\TestStep\DeleteAllSalesRuleStep::class)->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.xml new file mode 100644 index 0000000000000..44735c6492544 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/ShoppingCartWithFreeShippingTest.xml @@ -0,0 +1,25 @@ + + + + + + rule_with_freeshipping_by_weight + default + 560.00 + 0.00 + 560.00 + + + rule_with_freeshipping_by_weight + simple_with_weight_10 + 560.00 + 5.00 + 565.00 + + + diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/UpdateSalesRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/UpdateSalesRuleEntityTest.php index 92dc0f4f83956..c36a9b8bb7bb3 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/UpdateSalesRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/UpdateSalesRuleEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/ApplySalesRuleOnBackendStep.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/ApplySalesRuleOnBackendStep.php index 88288409bc631..d4ccd3815b574 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/ApplySalesRuleOnBackendStep.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestStep/ApplySalesRuleOnBackendStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/testcase.xml index 37f8366674e05..7bc66f48587ef 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/testcase.xml @@ -1,7 +1,7 @@ @@ -32,8 +32,8 @@ - - + + diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/webapi/di.xml index 5cb99f6be1287..7e6120fff7780 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/Edit/SynonymGroupForm.php b/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/Edit/SynonymGroupForm.php index 7d59820a235e4..c9a22d373b825 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/Edit/SynonymGroupForm.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/Edit/SynonymGroupForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/SynonymGroupGrid.php b/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/SynonymGroupGrid.php index 5355031b005de..440f1b3ad924a 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/SynonymGroupGrid.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Block/Adminhtml/Block/SynonymGroupGrid.php @@ -1,6 +1,6 @@ '[name="scope_id"]', 'input' => 'simplifiedselect' ], + 'group_id' => [ + 'selector' => '[name="group_id"]', + ], + 'website_id' => [ + 'selector' => '[name="website_id"]', + 'input' => 'select', + ], ]; /** diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php index 3273f033bb522..68a7bfcf50ed9 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php @@ -1,6 +1,6 @@ open(); - $data = $synonymGroup->getData(); - $filter = [ - 'synonyms' => $data['synonyms'], - ]; - $synonymGroupIndex->getSynonymGroupGrid()->search($filter); + $this->prepareFilter($synonymGroup, $synonymFilter); + $synonymGroupIndex->getSynonymGroupGrid()->search($this->filter); \PHPUnit_Framework_Assert::assertTrue( - $synonymGroupIndex->getSynonymGroupGrid()->isRowVisible($filter, false, false), - 'Synonym Group with ' - . 'synonyms \'' . $filter['synonyms'] . '\', ' - . 'is absent in Synonym grid.' + $synonymGroupIndex->getSynonymGroupGrid()->isRowVisible($this->filter, false, false), + 'Synonym Group is absent in Synonym grid' + ); + + \PHPUnit_Framework_Assert::assertEquals( + count($synonymGroupIndex->getSynonymGroupGrid()->getAllIds()), + 1, + 'There is more than one synonyms founded' ); } + /** + * Prepare filter for search synonyms. + * + * @param SynonymGroup $synonymGroup + * @param array|null $synonymFilter + * @return void + */ + private function prepareFilter(SynonymGroup $synonymGroup, $synonymFilter = null) + { + $data = $synonymGroup->getData(); + $this->filter = [ + 'synonyms' => $data['synonyms'], + 'website_id' => isset($synonymFilter['data']['website']) + ? $synonymFilter['data']['website'] + : '', + 'group_id' => isset($synonymFilter['data']['id']) + ? $synonymFilter['data']['id'] + : '', + ]; + } + /** * Returns a string representation of the object. * diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php index b5556fa7991ce..8549645ad96c3 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php @@ -1,6 +1,6 @@ open(); + foreach ($searchQueries as $query) { + $synonymGroupIndex->getSynonymGroupGrid()->fullTextSearch($query['query']); + foreach ($query['results'] as $key => $result) { + \PHPUnit_Framework_Assert::assertEquals( + $result, + $synonymGroupIndex->getSynonymGroupGrid()->isRowVisible( + ['synonyms' => $synonymGroups[$key]->getData()['synonyms']], + false, + false + ), + sprintf( + 'Synonym Group with synonyms \'%s\' is %s in the grid. Search query: %s', + $synonymGroups[$key]->getData()['synonyms'], + $result ? 'absent' : 'present', + $query['query'] + ) + ); + } + $synonymGroupIndex->getSynonymGroupGrid()->resetFilter(); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Results of search by keyword are correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php index e083af58f3113..3edebc22483f8 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php @@ -1,6 +1,6 @@ open(); + + \PHPUnit_Framework_Assert::assertContains( + self::ACCESS_DENIED_TEXT, + $dashboard->getErrorBlock()->getContent(), + 'Synonym group index page is available.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Access to synonym group index page by direct url is restricted.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml b/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml index 315b933f43a32..7e27984411b99 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup/ScopeId.php b/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup/ScopeId.php index 7bc0e92c9022b..ba3c4fb5855fd 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup/ScopeId.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup/ScopeId.php @@ -1,6 +1,6 @@ @@ -9,6 +9,6 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Page/Adminhtml/SynonymGroupNew.xml b/dev/tests/functional/tests/app/Magento/Search/Test/Page/Adminhtml/SynonymGroupNew.xml index e130c35976900..f08187a405ff0 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Page/Adminhtml/SynonymGroupNew.xml +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Page/Adminhtml/SynonymGroupNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Repository/SynonymGroup.xml b/dev/tests/functional/tests/app/Magento/Search/Test/Repository/SynonymGroup.xml index 1a025212e0db6..18cf0415163b8 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Repository/SynonymGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Repository/SynonymGroup.xml @@ -1,7 +1,7 @@ @@ -14,5 +14,29 @@ test_synonym_%isolation%,test_synonym_2_test_synonym_%isolation% Yes + + + + all_store_views + + synonym_1_group_1,synonym_2_group_1 + No + + + + + all_store_views + + synonym_1_group_2,synonym_2_group_2,synonym_3_group_2 + No + + + + + all_store_views + + synonym_1_group_3,synonym_2_group_3 + No + diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/AdvancedSearchWithAttributeTest.php b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/AdvancedSearchWithAttributeTest.php new file mode 100644 index 0000000000000..dca2418eaa9ff --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/AdvancedSearchWithAttributeTest.php @@ -0,0 +1,391 @@ + System -> New Index Management + * 2. Product EAV = Update by Schedule + * Cron is turned off. + * 3. Perform full reindex: "bin/magento indexer:reindex". + * Steps: + * 1. Call assert to check index status (Product EAV indexer: Status = Ready) + * 2. Open Backend -> Stores -> Attributes -> Product + * 3. Open Weight attribute + * 4. Update and save attribute to: + * Use in Advanced Search = Yes + * 5. Call assert to check index status (Product EAV indexer: Status = Required Reindex) + * 6. Assert that weight attribute is available on the Advanced Search + * 7. Run Full reindex from console + * 8. Change Weight attribute and save + * Scope = Website (Advanced Attribute Properties) + * 10. Call assert to check index status (Product EAV indexer: Status = Required Reindex) + * 11. Assert that weight attribute is available on the Advanced Search + * 12. Run Full reindex from console + * 13. Create simple product with default attribute set with weight = 1 + * 14. Create grouped product so that it will include simple product as option + * 15. Create bundle product so that it will include simple product as option + * 16. Create configurable product with one option product for which weight = 2 + * 17. Call assert to check index status (Product EAV indexer: Status = Ready + * 18. Open Advanced Search on frontend + * 19. Enter value to Weight = 1 and click Search button + * 20. Assert that page with 3 products is open: + * Simple + * Bundle + * Grouped + * 21. Update Weight Attribute in Backend + * Use in Advanced Search = No + * 22. Call assert to check index status (Product EAV indexer: Status = Required Reindex) + * 23. Assert that weight attribute is absent the Advanced Search + * 24. Run Full reindex from console + * + * @group Search + * @ZephyrId MAGETWO-25931 + * @SuppressWarnings(PHPMD.TooManyFields) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class AdvancedSearchWithAttributeTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + /* end tags */ + + /** + * Assert that Attribute is present in Advanced Search Page. + * + * @var AssertSearchAttributeTest + */ + private $assertSearchAttributeTest; + + /** + * Products for search + * + * @var array + */ + private $products; + + /** + * Attribute for check in Advanced Search Page. + * + * @var string + */ + private $attributeForSearch; + + /** + * Default weight attribute value. + * + * @var CatalogProductAttribute + */ + private $attributeDisable; + + /** + * Indexers in Index Management Page. + * + * @var array + */ + private $indexers; + + /** + * Advanced Search Page. + * + * @var AdvancedSearch + */ + private $advancedSearch; + + /** + * Index Management Page. + * + * @var IndexManagement + */ + private $indexManagement; + + /** + * Perform bin/magento commands from command line for functional tests executions. + * + * @var Indexer + */ + private $cli; + + /** + * Advanced Result Page. + * + * @var ResultPage + */ + private $resultPage; + + /** + * Catalog Product Index Page. + * + * @var ProductGrid + */ + private $productGrid; + + /** + * Catalog Product New Page. + * + * @var NewProductPage + */ + private $newProductPage; + + /** + * Catalog Product Edit Page. + * + * @var ProductEdit + */ + private $productEdit; + + /** + * Catalog Product Attribute New Page. + * + * @var AttributeNewPage + */ + private $attributeNewPage; + + /** + * Assert Indexer Status. + * + * @var AssertIndexerStatus + */ + private $assertIndexerStatus; + + /** + * Assert Creation Product. + * + * @var AssertProductSaveMessage + */ + private $assertCreateProducts; + + /** + * Assert Creation Product. + * + * @var CatalogProductAttributeIndex + */ + private $productAttributePage; + + /** + * Assert Success Message Indexer Update by Schedule. + * + * @var AssertSuccessSaveMessage + */ + private $assertSuccessSaveMessage; + + /** + * Assert Success Message is Present After Save Attribute. + * + * @var AssertAdvancedSearchResult + */ + private $assertAdvancedSearchResult; + + /** + * Assert Products in Advanced Search Result Page. + * + * @var AssertAttributeStatus + */ + private $assertAttributeStatus; + + /** + * Inject pages. + * + * @param IndexManagement $indexManagement + * @param AdvancedSearch $advancedSearch + * @param AdvancedResult $resultPage + * @param CatalogProductIndex $productGrid + * @param CatalogProductNew $newProductPage + * @param CatalogProductEdit $productEdit + * @param AssertIndexerStatus $assertIndexerStatus + * @param AssertProductSaveMessage $assertCreateProducts + * @param CatalogProductAttributeIndex $productAttributePage + * @param CatalogProductAttributeNew $attributeNewPage + * @param AssertSuccessSaveMessage $assertSuccessSaveMessage + * @param AssertSearchAttributeTest $assertSearchAttributeTest + * @param AssertAdvancedSearchProductResult $assertAdvancedSearchResult + * @param AssertProductAttributeSaveMessage $assertAttributeStatus + * @return void + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __inject( + IndexManagement $indexManagement, + AdvancedSearch $advancedSearch, + AdvancedResult $resultPage, + CatalogProductIndex $productGrid, + CatalogProductNew $newProductPage, + CatalogProductEdit $productEdit, + AssertIndexerStatus $assertIndexerStatus, + AssertProductSaveMessage $assertCreateProducts, + CatalogProductAttributeIndex $productAttributePage, + CatalogProductAttributeNew $attributeNewPage, + AssertSuccessSaveMessage $assertSuccessSaveMessage, + AssertSearchAttributeTest $assertSearchAttributeTest, + AssertAdvancedSearchProductResult $assertAdvancedSearchResult, + AssertProductAttributeSaveMessage $assertAttributeStatus + ) { + $this->indexManagement = $indexManagement; + $this->advancedSearch = $advancedSearch; + $this->resultPage = $resultPage; + $this->productGrid = $productGrid; + $this->newProductPage = $newProductPage; + $this->productEdit = $productEdit; + $this->assertIndexerStatus = $assertIndexerStatus; + $this->assertCreateProducts = $assertCreateProducts; + $this->productAttributePage = $productAttributePage; + $this->attributeNewPage = $attributeNewPage; + $this->assertSuccessSaveMessage = $assertSuccessSaveMessage; + $this->assertSearchAttributeTest = $assertSearchAttributeTest; + $this->assertAdvancedSearchResult = $assertAdvancedSearchResult; + $this->assertAttributeStatus = $assertAttributeStatus; + } + + /** + * Use Advanced Search by Decimal indexable attribute if Edit/Add Attribute. + * + * @param Indexer $cli + * @param Category $category + * @param FixtureFactory $fixtureFactory + * @param CatalogProductSimple $productSearch + * @param CatalogProductAttribute $attributeEnable + * @param CatalogProductAttribute $attributeDisable + * @param CatalogProductAttribute $attributeGlobalStatus + * @param string $attributeForSearch + * @param array $isVisibleInAdvancedSearch + * @param array $productDropDownList + * @param array $products + * @param string|null $indexers + * @return void + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function test( + Indexer $cli, + Category $category, + FixtureFactory $fixtureFactory, + CatalogProductSimple $productSearch, + CatalogProductAttribute $attributeEnable, + CatalogProductAttribute $attributeDisable, + CatalogProductAttribute $attributeGlobalStatus, + $attributeForSearch, + array $isVisibleInAdvancedSearch, + array $productDropDownList, + array $products, + $indexers = null + ) { + $this->cli = $cli; + $this->products = $products; + $this->attributeDisable = $attributeDisable; + $this->attributeForSearch = $attributeForSearch; + $this->indexers = explode(',', $indexers); + + $category->persist(); + + // Indexers Update bu Schedule + $this->indexManagement->open(); + $this->indexManagement->getMainBlock()->updateBySchedule($this->indexers); + //Assert attribute Update by Schedule + $this->assertSuccessSaveMessage->processAssert($this->indexManagement, $this->indexers); + + // Full indexers reindex + $cli->reindex(); + // Assert indexers status + $this->assertIndexerStatus->processAssert($this->indexManagement, $this->indexers); + $this->productAttributePage->open(); + $this->productAttributePage->getGrid()->searchAndOpen(['attribute_code' => $attributeForSearch['name']]); + $this->attributeNewPage->getAttributeForm()->fill($attributeEnable); + $this->attributeNewPage->getPageActions()->save(); + // Assert attribute status + $this->assertAttributeStatus->processAssert($this->productAttributePage); + + // Assert indexers status + $this->assertIndexerStatus->processAssert($this->indexManagement, $this->indexers, false); + + $this->assertSearchAttributeTest->processAssert($this->advancedSearch, $attributeForSearch); + $cli->reindex(); + + // Change attribute 'scope mode' + $this->productAttributePage->open(); + $this->productAttributePage->getGrid()->searchAndOpen(['attribute_code' => $attributeForSearch['name']]); + $this->attributeNewPage->getAttributeForm()->fill($attributeGlobalStatus); + $this->attributeNewPage->getPageActions()->save(); + // Assert attribute status + $this->assertAttributeStatus->processAssert($this->productAttributePage); + + // Assert indexers status + $this->assertIndexerStatus->processAssert($this->indexManagement, $this->indexers, false); + + // Assert advanced attribute is present(or absent) in Advanced Search Page. + $this->assertSearchAttributeTest->processAssert($this->advancedSearch, $attributeForSearch); + $cli->reindex(); + + // Create Products + $allProducts = []; + foreach ($products as $key => $product) { + list($fixtureCode, $dataset) = explode('::', $product); + $this->productGrid->open(); + $this->productGrid->getGridPageActionBlock()->addProduct($productDropDownList[$key]); + $product = $fixtureFactory->createByCode($fixtureCode, ['dataset' => $dataset]); + $this->newProductPage->getProductForm()->fill($product, null, $category); + $this->newProductPage->getFormPageActions()->save($product); + + $this->assertCreateProducts->processAssert($this->productEdit); + $allProducts[] = $product; + } + + $cli->reindex(); + $this->advancedSearch->open(); + $this->advancedSearch->getForm()->fill($productSearch)->submit(); + + // Assert that Advanced Search result page contains only product(s) according to requested from fixture + $this->assertAdvancedSearchResult->processAssert($isVisibleInAdvancedSearch, $allProducts, $this->resultPage); + $this->productAttributePage->open(); + $this->productAttributePage->getGrid()->searchAndOpen(['attribute_code' => $this->attributeForSearch['name']]); + $this->attributeNewPage->getAttributeForm()->fill($this->attributeDisable); + $this->attributeNewPage->getPageActions()->save(); + // Assert attribute status + $this->assertAttributeStatus->processAssert($this->productAttributePage); + + $this->assertIndexerStatus->processAssert($this->indexManagement, $this->indexers, false); + $cli->reindex(); + unset($this->attributeForSearch['isVisible']); + $this->assertSearchAttributeTest->processAssert($this->advancedSearch, $this->attributeForSearch); + } + + /** + * Set attribute default value. + * + * @return void + */ + protected function tearDown() + { + $this->productAttributePage->open(); + $this->productAttributePage->getGrid()->searchAndOpen(['attribute_code' => $this->attributeForSearch['name']]); + $this->attributeNewPage->getAttributeForm()->fill($this->attributeDisable); + $this->attributeNewPage->getPageActions()->save(); + $this->indexManagement->open(); + $this->indexManagement->getMainBlock()->massaction([], 'Update on Save', false, 'Select All'); + $this->cli->reindex(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/AdvancedSearchWithAttributeTest.xml b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/AdvancedSearchWithAttributeTest.xml new file mode 100644 index 0000000000000..34ad66ba632cb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/AdvancedSearchWithAttributeTest.xml @@ -0,0 +1,38 @@ + + + + + + configurable + simple + bundle + grouped + No + Yes + Yes + Yes + Yes + Yes + Global + No + Website + configurableProduct::one_simple_product + catalogProductSimple::default + bundleProduct::default_with_one_simple_product + groupedProduct::withSimpleProduct_without_category + 1 + 1 + Product EAV + + Weight + true + + category_%isolation% + + + diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateMultipleSynonymGroupsTest.php b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateMultipleSynonymGroupsTest.php new file mode 100644 index 0000000000000..80c7045d9ddac --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateMultipleSynonymGroupsTest.php @@ -0,0 +1,73 @@ +fixtureFactory = $fixtureFactory; + } + + /** + * Create Synonym Groups. + * + * @param array $synonymGroups + * @return array + */ + public function test(array $synonymGroups) + { + $groups = []; + foreach ($synonymGroups as $key => $dataset) { + $groups[$key] = $this->fixtureFactory->createByCode('synonymGroup', ['dataset' => $dataset]); + $groups[$key]->persist(); + } + + return [ + 'synonymGroups' => $groups, + ]; + } + + /** + * Delete all synonym groups. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create(\Magento\Search\Test\TestStep\DeleteAllSynonymGroupsStep::class)->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateMultipleSynonymGroupsTest.xml b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateMultipleSynonymGroupsTest.xml new file mode 100644 index 0000000000000..bb1d41de1b17f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateMultipleSynonymGroupsTest.xml @@ -0,0 +1,60 @@ + + + + + + MAGETWO-63120: Search icon is disabled on collapsed toolbar + synonym_group_1 + synonym_group_2 + synonym_group_3 + + + synonym_undefined + + false + false + false + + + + synonym_1_group_1 + + true + false + false + + + + synonym_1_group_2 synonym_undefined + + false + true + false + + + + synonym_1_group_1 synonym_2_group_2 + + true + true + false + + + + synonym_1_group_1 synonym_2_group_2 synonym_1_group_3 synonym_undefined + + true + true + true + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateSynonymGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateSynonymGroupEntityTest.php index ce2222ba3dd2c..31f46fbcae671 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateSynonymGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CreateSynonymGroupEntityTest.php @@ -1,6 +1,6 @@ @@ -25,7 +25,7 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, stable:no synonym_%isolation% custom_store diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CustomAclPermissionTest.xml b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CustomAclPermissionTest.xml new file mode 100644 index 0000000000000..0275674a19e10 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/CustomAclPermissionTest.xml @@ -0,0 +1,17 @@ + + + + + + custom_admin_with_role_without_synonym + Marketing > Search Synonyms + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/DeleteSynonymGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/DeleteSynonymGroupEntityTest.php index 7e6ec5c14da6d..d7a8d77aae515 100755 --- a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/DeleteSynonymGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/DeleteSynonymGroupEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/MergeSynonymGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/MergeSynonymGroupEntityTest.php index 4e9424a83be02..4134b9fbe4a87 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/MergeSynonymGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/MergeSynonymGroupEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/UpdateSynonymGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/UpdateSynonymGroupEntityTest.php index 042a656339abb..7e32a5c0f563b 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/UpdateSynonymGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestCase/UpdateSynonymGroupEntityTest.php @@ -1,6 +1,6 @@ + test_type:extended_acceptance_test, to_maintain:yes prepareMerge Update Synonym Groups Successfully - test_type:extended_acceptance_test new_synonym_%isolation% all_store_views diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/TestStep/DeleteAllSynonymGroupsStep.php b/dev/tests/functional/tests/app/Magento/Search/Test/TestStep/DeleteAllSynonymGroupsStep.php new file mode 100644 index 0000000000000..b21ebe5d32177 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Search/Test/TestStep/DeleteAllSynonymGroupsStep.php @@ -0,0 +1,43 @@ +synonymGroupIndex = $synonymGroupIndex; + } + + /** + * Delete synonym groups on backend. + * + * @return void + */ + public function run() + { + $this->synonymGroupIndex->open(); + $this->synonymGroupIndex->getSynonymGroupGrid()->resetFilter(); + $this->synonymGroupIndex->getSynonymGroupGrid()->massaction([], 'Delete', true, 'Select All'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Search/Test/etc/curl/di.xml index 3ad5243435072..3541f04fcdaf9 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Search/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Search/Test/etc/di.xml index 7e32c2c5ea687..723e367d1b5dd 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Search/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Block/Form/ForgotPassword.php b/dev/tests/functional/tests/app/Magento/Security/Test/Block/Form/ForgotPassword.php index e7c84cd1bdc8d..5046cc09567ed 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Block/Form/ForgotPassword.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Block/Form/ForgotPassword.php @@ -1,6 +1,6 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerEmailChanged.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerEmailChanged.php new file mode 100644 index 0000000000000..beefb55ca736f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerEmailChanged.php @@ -0,0 +1,64 @@ +createByCode( + 'customer', + [ + 'data' => [ + 'email' => $customer->getEmail(), + 'password' => $initialCustomer->getPassword() + ], + ] + ); + + $this->objectManager->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $customer] + )->run(); + + \PHPUnit_Framework_Assert::assertTrue( + $customerAccountIndex->getAccountMenuBlock()->isVisible(), + 'Customer Account Dashboard is not visible.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Customer email was changed.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php index de4bdd1f780aa..b7fb928107b62 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php @@ -1,6 +1,6 @@ getRegisterForm()->getPasswordError(); + $characterClassesNumber = $config + ->getData('section')['customer/password/required_character_classes_number']['value']; + + \PHPUnit_Framework_Assert::assertEquals( + sprintf(self::EXPECTED_MAX_CHARACTERS, $characterClassesNumber) . self::EXPECTED_MESSAGE, + $errorMessage, + 'Wrong expected message is displayed.' + . "\nExpected: " . sprintf(self::EXPECTED_MAX_CHARACTERS, $characterClassesNumber) . self::EXPECTED_MESSAGE + . "\nActual: " . $errorMessage + ); + } + + /** + * Text of success register message is displayed. + * + * @return string + */ + public function toString() + { + return "Customer's password is not correct."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php index dcc81b875ff9a..07a89dd4054ec 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php @@ -1,6 +1,6 @@ getAccountInfoForm(); + + \PHPUnit_Framework_Assert::assertFalse( + $infoForm->isEmailVisible(), + 'Email text field should not be visible.' + ); + + \PHPUnit_Framework_Assert::assertFalse( + $infoForm->isCurrentPasswordVisible(), + 'Current Password text field should not be visible.' + ); + + \PHPUnit_Framework_Assert::assertFalse( + $infoForm->isPasswordVisible(), + 'New Password text field should not be visible.' + ); + + \PHPUnit_Framework_Assert::assertFalse( + $infoForm->isConfirmPasswordVisible(), + 'Password Confirmation text field should not be visible.' + ); + } + + /** + * String representation of success assert. + * + * @return string + */ + public function toString() + { + return 'Default customer account information tab is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php index f65c4324418ef..2f66f2506c717 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php @@ -1,6 +1,6 @@ @@ -23,6 +23,14 @@ 10 + + + customer + 1 + 10 + 3 + + admin diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php index cc75c27949c0e..22244f1b8759f 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewIntegrationTest.php @@ -1,6 +1,6 @@ + severity:S2 user_lockout_failures custom_admin_with_default_role Integration%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php index 23a43100de854..bf218952dd415 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewRoleTest.php @@ -1,6 +1,6 @@ + severity:S2 user_lockout_failures custom_admin_with_default_role AdminRole%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.php new file mode 100644 index 0000000000000..4c47edf9d5548 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.php @@ -0,0 +1,134 @@ + All Users. + * 3. Click on Add New User. + * 4. Fill in all data according to data set (password is incorrect). + * 5. Perform action 4 specified number of times. + * 6. "You have entered an invalid password for current user." appears after each attempt. + * 7. Perform all assertions. + * + * @ZephyrId MAGETWO-49034 + */ +class LockAdminUserWhenCreatingNewUserTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + const SEVERITY = 'S2'; + /* end tags */ + + /** + * User grid page + * + * @var UserIndex + */ + protected $userIndexPage; + + /** + * User new/edit page + * + * @var UserEdit + */ + protected $userEditPage; + + /** + * Configuration setting. + * + * @var string + */ + protected $configData; + + /** + * @var AdminAuthLogin page + */ + protected $adminAuthLogin; + + /** + * Setup data for test. + * @param UserIndex $userIndex + * @param UserEdit $userEdit + * @param AdminAuthLogin $adminAuthLogin + */ + public function __inject( + UserIndex $userIndex, + UserEdit $userEdit, + AdminAuthLogin $adminAuthLogin + ) { + $this->userIndexPage = $userIndex; + $this->userEditPage = $userEdit; + $this->adminAuthLogin = $adminAuthLogin; + } + + /** + * Runs Lock admin user when creating new user test. + * + * @param int $attempts + * @param User $customAdmin, + * @param User $user, + * @param string $configData + * @return void + */ + public function test( + $attempts, + User $customAdmin, + User $user, + $configData + ) { + $this->configData = $configData; + + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + $customAdmin->persist(); + + // Steps + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + $this->userIndexPage->open(); + $this->userIndexPage->getPageActions()->addNew(); + for ($i = 0; $i < $attempts; $i++) { + $this->userEditPage->getUserForm()->fill($user); + $this->userEditPage->getPageActions()->save(); + } + + // Reload + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml new file mode 100644 index 0000000000000..429b31f7f58c8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml @@ -0,0 +1,25 @@ + + + + + + user_lockout_failures + severity:S2 + custom_admin_with_default_role + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123q + 123123q + incorrect password + 4 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.php new file mode 100644 index 0000000000000..dccedd67097a6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.php @@ -0,0 +1,143 @@ + Extensions > Integrations. + * 3. Start to edit existing Integration. + * 4. Fill in all data according to data set (password is incorrect). + * 5. Perform action 4 specified number of times. + * 6. "You have entered an invalid password for current user." appears after each attempt. + * 7. Perform all assertions. + * + * @ZephyrId MAGETWO-49039 + */ +class LockAdminUserWhenEditingIntegrationTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + const SEVERITY = 'S2'; + /* end tags */ + + /** + * Integration grid page. + * + * @var IntegrationIndex + */ + protected $integrationIndexPage; + + /** + * Integration new page. + * + * @var IntegrationNew + */ + protected $integrationNewPage; + + /** + * Configuration setting. + * + * @var string + */ + protected $configData; + + /** + * @var AdminAuthLogin + */ + protected $adminAuthLogin; + + /** + * Preparing pages for test. + * + * @param IntegrationIndex $integrationIndex + * @param IntegrationNew $integrationNew + * @param AdminAuthLogin $adminAuthLogin + * @return void + */ + public function __inject( + IntegrationIndex $integrationIndex, + IntegrationNew $integrationNew, + AdminAuthLogin $adminAuthLogin + ) { + $this->integrationIndexPage = $integrationIndex; + $this->integrationNewPage = $integrationNew; + $this->adminAuthLogin = $adminAuthLogin; + } + + /** + * Run Lock user when creating new integration test. + * + * @param Integration $initintegration + * @param Integration $integration + * @param int $attempts + * @param User $customAdmin + * @param string $configData + * @return void + */ + public function test( + Integration $initintegration, + Integration $integration, + $attempts, + User $customAdmin, + $configData + ) { + $this->configData = $configData; + + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + $customAdmin->persist(); + $initintegration->persist(); + + // login to backend with new user + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + + // Steps + $filter = ['name' => $initintegration->getName()]; + $this->integrationIndexPage->open(); + $this->integrationIndexPage->getIntegrationGrid()->searchAndOpen($filter); + for ($i = 0; $i < $attempts; $i++) { + $this->integrationNewPage->getIntegrationForm()->fill($integration); + $this->integrationNewPage->getFormPageActions()->save(); + } + + // Reload page + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.xml new file mode 100644 index 0000000000000..f67a2c3d35c56 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingIntegrationTest.xml @@ -0,0 +1,21 @@ + + + + + + user_lockout_failures + severity:S2 + custom_admin_with_default_role + default_active + Integration%isolation% + incorrect password + 4 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.php new file mode 100644 index 0000000000000..30513be8f6eb8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.php @@ -0,0 +1,140 @@ + User Roles. + * 3. Start editing existing User Role. + * 4. Fill in all data according to data set (password is incorrect). + * 5. Perform action 4 specified number of times. + * 6. Admin account is locked. + * 7. Perform all assertions. + * + * @ZephyrId MAGETWO-49037 + * @Group Security + * + */ +class LockAdminUserWhenEditingRoleTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + const SEVERITY = 'S2'; + /* end tags */ + + /** + * UserRoleIndex page. + * + * @var UserRoleIndex + */ + protected $userRoleIndex; + + /** + * UserRoleEditRole page. + * + * @var UserRoleEditRole + */ + protected $userRoleEditRole; + + /** + * Configuration setting. + * + * @var string + */ + protected $configData; + + /** + * Admin login Page. + * + * @var AdminAuthLogin + */ + protected $adminAuthLogin; + + /** + * Setup data for test. + * + * @param UserRoleIndex $userRoleIndex + * @param UserRoleEditRole $userRoleEditRole + * @param AdminAuthLogin $adminAuthLogin + * @return void + */ + public function __inject( + UserRoleIndex $userRoleIndex, + UserRoleEditRole $userRoleEditRole, + AdminAuthLogin $adminAuthLogin + ) { + $this->userRoleIndex = $userRoleIndex; + $this->userRoleEditRole = $userRoleEditRole; + $this->adminAuthLogin = $adminAuthLogin; + } + + /** + * Runs Lock admin user when editing existing role test. + * + * @param Role $role + * @param Role $initrole + * @param int $attempts + * @param User $customAdmin + * @param string $configData + * @return void + */ + public function test( + Role $role, + Role $initrole, + $attempts, + User $customAdmin, + $configData + ) { + $this->configData = $configData; + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + $customAdmin->persist(); + $initrole->persist(); + // Steps login to backend with new user + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + $filter = ['rolename' => $initrole->getRolename()]; + $this->userRoleIndex->open(); + $this->userRoleIndex->getRoleGrid()->searchAndOpen($filter); + for ($i = 0; $i < $attempts; $i++) { + $this->userRoleEditRole->getRoleFormTabs()->fill($role); + $this->userRoleEditRole->getPageActions()->save(); + } + // Reload + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.xml new file mode 100644 index 0000000000000..b7eb881e91161 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingRoleTest.xml @@ -0,0 +1,22 @@ + + + + + + user_lockout_failures + severity:S2 + default + custom_admin_with_default_role + NewAdminRole%isolation% + incorrect password + All + 4 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.php new file mode 100644 index 0000000000000..fdee3c635e824 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.php @@ -0,0 +1,133 @@ + All Users. + * 3. Start editing existing User. + * 4. Fill in all data according to data set (password is incorrect). + * 5. Perform action 4 specified number of times. + * 6. Admin account is locked. + * 7. Perform all assertions. + * + * @ZephyrId MAGETWO-49035 + */ +class LockAdminUserWhenEditingUserTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + const SEVERITY = 'S2'; + /* end tags */ + + /** + * User grid page + * + * @var UserIndex + */ + protected $userIndexPage; + + /** + * User edit page + * + * @var UserEdit + */ + protected $userEditPage; + + /** + * @var $configData + */ + protected $configData; + + /** + * @var AdminAuthLogin page + */ + protected $adminAuthLogin; + + /** + * Setup data for test. + * @param UserIndex $userIndex + * @param UserEdit $userEdit + * @param AdminAuthLogin $adminAuthLogin + */ + public function __inject( + UserIndex $userIndex, + UserEdit $userEdit, + AdminAuthLogin $adminAuthLogin + ) { + $this->userIndexPage = $userIndex; + $this->userEditPage = $userEdit; + $this->adminAuthLogin = $adminAuthLogin; + } + + /** + * Runs Lock admin user when editing existing role test. + * + * @param User $user + * @param int $attempts + * @param User $customAdmin + * @param string $configData + * @return void + */ + public function test( + $attempts, + User $customAdmin, + User $user, + $configData + ) { + $this->configData = $configData; + + // Preconditions + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + $customAdmin->persist(); + + // Steps login to backend with new user + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + // Select user to edit. + $filter = ['username' => $customAdmin->getUsername()]; + $this->userIndexPage->open(); + $this->userIndexPage->getUserGrid()->searchAndOpen($filter); + // Edit user with wrong password + for ($i = 0; $i < $attempts; $i++) { + $this->userEditPage->getUserForm()->fill($user); + $this->userEditPage->getPageActions()->save(); + } + // Reload + $this->adminAuthLogin->open(); + $this->adminAuthLogin->getLoginBlock()->fill($customAdmin); + $this->adminAuthLogin->getLoginBlock()->submit(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.xml new file mode 100644 index 0000000000000..6c9787646d874 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenEditingUserTest.xml @@ -0,0 +1,25 @@ + + + + + + user_lockout_failures + severity:S2 + custom_admin_with_default_role + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123qq + 123123qq + incorrect password + 4 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnEditPageTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnEditPageTest.php index c5b910c124707..2ecad7c2e717c 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnEditPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnEditPageTest.php @@ -1,6 +1,6 @@ + severity:S1, to_maintain:yes customer_max_login_failures_number default incorrect password 123123^a 123123^a - 6 + 7 diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnLoginPageTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnLoginPageTest.php index 1612f1dac24e4..b6ff096209ff8 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnLoginPageTest.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockCustomerOnLoginPageTest.php @@ -1,6 +1,6 @@ + severity:S1, to_maintain:yes customer_max_login_failures_number default incorrect password diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewCustomerPasswordComplexityTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewCustomerPasswordComplexityTest.php index 8fdab9165db03..0505b864680d0 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewCustomerPasswordComplexityTest.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/NewCustomerPasswordComplexityTest.php @@ -1,6 +1,6 @@ + severity:S1 john doe johndoe%isolation%@example.com @@ -17,6 +18,7 @@ + severity:S1 john doe johndoe%isolation%@example.com diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/RegisterCustomerEntityWithDifferentPasswordClassesTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/RegisterCustomerEntityWithDifferentPasswordClassesTest.php new file mode 100644 index 0000000000000..5b5ffaa173ee1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/RegisterCustomerEntityWithDifferentPasswordClassesTest.php @@ -0,0 +1,111 @@ +customerAccountCreate = $customerAccountCreate; + $this->cmsIndex = $cmsIndex; + $this->testStepFactory = $testStepFactory; + } + + /** + * Create Customer account on Storefront. + * + * @param Customer $customer + * @param ConfigData $config + * @return void + */ + public function test(Customer $customer, ConfigData $config) + { + // Preconditions + $config->persist(); + // Steps + $this->cmsIndex->open(); + $this->cmsIndex->getLinksBlock()->openLink('Create an Account'); + $this->customerAccountCreate->getRegisterForm()->registerCustomer($customer); + + $characterClassesNumber = $config + ->getData('section')['customer/password/required_character_classes_number']['value']; + + return ['characterClassesNumber' => $characterClassesNumber]; + } + + /** + * Set default settings and logout customer. + * + * @return void + */ + protected function tearDown() + { + //Set default required character classes for the password + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => 'default_required_character_classes_number'] + )->run(); + // Logout customer + $this->testStepFactory->create( + \Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/RegisterCustomerEntityWithDifferentPasswordClassesTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/RegisterCustomerEntityWithDifferentPasswordClassesTest.xml new file mode 100644 index 0000000000000..cfd53b4ef98ed --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/RegisterCustomerEntityWithDifferentPasswordClassesTest.xml @@ -0,0 +1,95 @@ + + + + + + default_required_character_classes_number + + + 1 + + + register_customer + 12345678 + 12345678 + + + + default_required_character_classes_number + + + 2 + + + register_customer + abc12345 + abc12345 + + + + default_required_character_classes_number + + + 2 + + + register_customer + 12345678 + 12345678 + + + + default_required_character_classes_number + + + 3 + + + register_customer + abcXYZ123 + abcXYZ123 + + + + default_required_character_classes_number + + + 3 + + + register_customer + abc12345 + abc12345 + + + + default_required_character_classes_number + + + 4 + + + register_customer + abcXYZ12^ + abcXYZ12^ + + + + default_required_character_classes_number + + + 4 + + + register_customer + abcXYZ123 + abcXYZ123 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.php index d3b7a3ccb1304..59469df1291ac 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.php @@ -1,6 +1,6 @@ + severity:S1 customer_US 2 diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.php index 0bf600a7042f9..06a02287107b0 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.php @@ -1,6 +1,6 @@ + severity:S1 custom_admin_with_default_role 2 diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerEmailTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerEmailTest.php new file mode 100644 index 0000000000000..51a4d629eed31 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerEmailTest.php @@ -0,0 +1,88 @@ +customerAccountEdit = $customerAccountEdit; + } + + /** + * Change customer password in Account Information tab. + * + * @param Customer $initialCustomer + * @param Customer $customer + * @return void + */ + public function test(Customer $initialCustomer, Customer $customer) + { + // Preconditions + $initialCustomer->persist(); + + // Steps + $this->objectManager->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $initialCustomer] + )->run(); + + $this->customerAccountEdit->getAccountMenuBlock()->openMenuItem('Account Information'); + $this->customerAccountEdit->getAccountInfoForm()->SetChangeEmail(true); + $this->customerAccountEdit->getAccountInfoForm()->fill($customer); + $this->customerAccountEdit->getAccountInfoForm()->submit(); + } + + /** + * Logout customer from frontend account. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerEmailTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerEmailTest.xml new file mode 100644 index 0000000000000..f2aaf11c2bef7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerEmailTest.xml @@ -0,0 +1,26 @@ + + + + + + severity:S1 + default + JaneDoe_%isolation%@example.com + 123123^q + + + + + severity:S2 + default + JaneDoe_%isolation%@example.com + 123123123 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerPasswordTest.php b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerPasswordTest.php new file mode 100644 index 0000000000000..5ac6f2af5c5ef --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerPasswordTest.php @@ -0,0 +1,91 @@ +customerAccountEdit = $customerAccountEdit; + } + + /** + * Change customer password in Account Information tab. + * + * @param Customer $initialCustomer + * @param Customer $customer + * @param boolean $check + * @return void + */ + public function test(Customer $initialCustomer, Customer $customer, $check) + { + // Preconditions + $initialCustomer->persist(); + + // Steps + $this->objectManager->create( + \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, + ['customer' => $initialCustomer] + )->run(); + + $this->customerAccountEdit->getAccountMenuBlock()->openMenuItem('Account Information'); + if ($check) { + $this->customerAccountEdit->getAccountInfoForm()->SetChangePassword(true); + $this->customerAccountEdit->getAccountInfoForm()->fill($customer); + $this->customerAccountEdit->getAccountInfoForm()->submit(); + } + } + + /** + * Logout customer from frontend account. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create(\Magento\Customer\Test\TestStep\LogoutCustomerOnFrontendStep::class)->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerPasswordTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerPasswordTest.xml new file mode 100644 index 0000000000000..8a52f35ad6d1d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/SecureChangingCustomerPasswordTest.xml @@ -0,0 +1,36 @@ + + + + + + severity:S1 + default + 123123^q + 123123Qa + 123123Qa + 1 + + + + + severity:S2 + default + 123123123 + 123123Qa + 123123Qa + 1 + + + + severity:S3 + default + 0 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Security/Test/etc/di.xml new file mode 100644 index 0000000000000..277309dc2d760 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Security/Test/etc/di.xml @@ -0,0 +1,39 @@ + + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S2 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Authentication.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Authentication.php index c381632ca4aa9..0d199a613c5c1 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Authentication.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Authentication.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/CreateBackup.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/CreateBackup.php index 4c3442784e5aa..0fa38e7d69b70 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/CreateBackup.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/CreateBackup.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Extension/AbstractGrid.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Extension/AbstractGrid.php index 24403ce94c52c..e40cfbb0fcfa4 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Extension/AbstractGrid.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/Extension/AbstractGrid.php @@ -1,6 +1,6 @@ waitForElementVisible($this->firstField); + $this->chooseShowAllVersions(); + return parent::fill($fixture, $element); } + /** + * Show all versions include unstable + * + * @return void + */ + private function chooseShowAllVersions() + { + $element = $this->_rootElement->find($this->showAllVersions, Locator::SELECTOR_CSS); + if ($element->isVisible()) { + $element->click(); + } + } + /** * Choose 'yes' for upgrade option called 'Other components' * diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.xml index eb594d124604f..18a98b07fb329 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SelectVersion.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SuccessMessage.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SuccessMessage.php index 327bb2867e44e..625198f425b93 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Block/SuccessMessage.php @@ -1,6 +1,6 @@ getSuccessMessage()->getUpdaterStatus(), diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php index 194f0285f83be..2abe2649f659c 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Extension.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Extension.xml index c772485bca650..ca460c8eb7466 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Extension.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Extension.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Module.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Module.xml index 563a00230efa7..0283d9359c140 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Module.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/RepoCredentials.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/RepoCredentials.xml index 0312bc769e5b7..c87564eecfc19 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/RepoCredentials.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/RepoCredentials.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Upgrade.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Upgrade.xml index 8c6e996bed1e5..4a7782eed02db 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Upgrade.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Fixture/Upgrade.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Page/Adminhtml/SetupWizard.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Page/Adminhtml/SetupWizard.xml index d8d6f828f2f93..db72fb506fc86 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Page/Adminhtml/SetupWizard.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Page/Adminhtml/SetupWizard.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/BackupOptions.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/BackupOptions.xml index 013384168e3d0..f9e97772f5dd4 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/BackupOptions.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/BackupOptions.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/Extension.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/Extension.xml index 319ae1a6ab81c..70da7c40bea27 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/Extension.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/Extension.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/RepoCredentials.xml b/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/RepoCredentials.xml index 2ae795ed9c7b8..d9760146c8298 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/RepoCredentials.xml +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Repository/RepoCredentials.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/AbstractExtensionTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/AbstractExtensionTest.php index f9358abe828c5..16dcf5edadbcc 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/AbstractExtensionTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/AbstractExtensionTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleTest.php index 128f9dafa397b..b89a3f4bb70f2 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleUpdateTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleUpdateTest.php index 8175dd27b5d57..1dce4b69eeb16 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleUpdateTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionMultipleUpdateTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionTest.php index 3dcceaeeb3b5a..3af2f076bf627 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/ExtensionTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php index 43c101176bdac..15992f150d6d0 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.php index f46b812ef0def..dd5937fc47705 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.php @@ -1,6 +1,6 @@ $product) { - $this->getItemsBlock()->getItemProductBlock($product)->fillProduct($data['items_data'][$key]); + $this->getItemsBlock()->getItemProductBlock($product->getSku())->fillProduct($data['items_data'][$key]); } } } diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.xml index 8840df25fdb0c..a30ace81bd2ea 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.xml +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items.php index 132c56c7d9c3e..0cdb42e03b910 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items.php @@ -1,6 +1,6 @@ productItem, $product->getSku()); + $selector = sprintf($this->productItem, $productSku); return $this->blockFactory->create( \Magento\Shipping\Test\Block\Adminhtml\Form\Items\Product::class, ['element' => $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)] diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items/Product.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items/Product.php index 2d8d21c07e956..66587c974b7c1 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items/Product.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Form/Items/Product.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Order/Tracking.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Order/Tracking.php index a7929cd128ab7..f28cf2fb70fc5 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Order/Tracking.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Order/Tracking.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Shipment/Grid.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Shipment/Grid.php index d3bd91eddc735..a8d0fc6a21c7e 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Shipment/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/Shipment/Grid.php @@ -1,6 +1,6 @@ 'input[name="order_increment_id"]', ], 'total_qty_from' => [ - 'selector' => 'input[name="total_qty[from]"', + 'selector' => 'input[name="total_qty[from]"]', ], 'total_qty_to' => [ - 'selector' => 'input[name="total_qty][to]"', + 'selector' => 'input[name="total_qty[to]"]', ], ]; } diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/View/Items.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/View/Items.php index efa08735cac0b..081bbfa10338f 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/View/Items.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Block/Adminhtml/View/Items.php @@ -1,6 +1,6 @@ getShippingMethodBlock()->isLoaderAppeared(), + 'Shipping rate has not been changed.' + ); + } + $shippingAvaialability = $isShippingAvailable ? 'avaiable' : 'unavailable'; + \PHPUnit_Framework_Assert::assertEquals( + $isShippingAvailable, + $checkoutOnepage->getShippingMethodBlock()->isShippingMethodAvaiable($shippingMethod), + "Shipping rates for {$shippingMethod['shipping_service']} should be $shippingAvaialability." + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return "Shipping rate has been changed."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php index dd83934bd7b07..0f7cdab9a6a73 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php @@ -1,6 +1,6 @@ $totalQty[$key], ]; \PHPUnit_Framework_Assert::assertTrue( - $salesOrderView->getOrderForm()->getTab('shipments')->getGridBlock()->isRowVisible($filter), + $salesOrderView + ->getOrderForm() + ->getTab('shipments') + ->getGridBlock() + ->isRowVisible($filter, true, false), 'Shipment is absent on shipments tab.' ); } diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php index 528d98e913324..cec7908556965 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php @@ -1,6 +1,6 @@ open(); + $orderId = $order->getId(); + $totalQty = $order->getTotalQtyOrdered(); + foreach ($ids['shipmentIds'] as $key => $shipmentIds) { + $filter = [ + 'id' => $shipmentIds, + 'order_id' => $orderId + ]; + $filterQty = [ + 'total_qty_from' => $totalQty[$key], + 'total_qty_to' => $totalQty[$key], + ]; + $shipmentIndex->getShipmentsGrid()->search($filter + $filterQty); + \PHPUnit_Framework_Assert::assertFalse( + $shipmentIndex->getShipmentsGrid()->isRowVisible($filter, false), + 'Shipment is present in shipment grid on shipment index page.' + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Shipment is absent in the shipment grid on shipment index page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php index 993e98a16cd1b..67e2aeb0a45af 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/OrderShipmentView.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/OrderShipmentView.xml index 1fc8042c59ef3..a8257dd3cd1db 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/OrderShipmentView.xml +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/OrderShipmentView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/SalesShipmentView.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/SalesShipmentView.xml index f0c8bca131085..1eedf8840b76e 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/SalesShipmentView.xml +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/SalesShipmentView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/ShipmentIndex.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/ShipmentIndex.xml index 81667dbbcc54d..f196d4d98cb0c 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/ShipmentIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/Adminhtml/ShipmentIndex.xml @@ -1,13 +1,13 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/SalesGuestPrint.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/SalesGuestPrint.xml index d4bd1455f71e6..3b706c1497953 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/SalesGuestPrint.xml +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/SalesGuestPrint.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/ShipmentView.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/ShipmentView.xml index 630c63fc3b897..ec2251406d5ea 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/ShipmentView.xml +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Page/ShipmentView.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/ConfigData.xml index a75e294ca859b..a44793238759f 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/Method.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/Method.php index b9a535ae1b663..aae0e98c40253 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/Method.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Repository/Method.php @@ -1,6 +1,6 @@ executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/CreateShipmentEntityTest.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/CreateShipmentEntityTest.php index 064bc2ec0ba2b..588b1b2cd1c97 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/CreateShipmentEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/CreateShipmentEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/SalesShippingReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/SalesShippingReportEntityTest.php new file mode 100644 index 0000000000000..f30ff18279577 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/SalesShippingReportEntityTest.php @@ -0,0 +1,64 @@ + Sales > Shipping. + * 2. Refresh statistic. + * 3. Configure and apply filter. + * 4. Remember report result. + * 5. Place order. + * 6. Create Shipping. + * 7. Refresh statistic. + * + * Steps: + * 1. Go to Reports > Sales > Shipping. + * 2. Configure and apply filter. + * 3. Perform all asserts. + * + * @ZephyrId MAGETWO-40914 + */ +class SalesShippingReportEntityTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + /* end tags */ + + /** + * Create shipment. + * + * @param SalesShippingReport $salesShippingReport + * @param OrderInjectable $order + * @param array shippingReport + * @return array + */ + public function test(SalesShippingReport $salesShippingReport, OrderInjectable $order, array $shippingReport) + { + // Preconditions + $salesShippingReport->open(); + $salesShippingReport->getMessagesBlock()->clickLinkInMessage('notice', 'here'); + $salesShippingReport->getFilterForm()->viewsReport($shippingReport); + $salesShippingReport->getActionBlock()->showReport(); + $initialShippingResult = $salesShippingReport->getGridBlock()->getLastResult(); + $initialShippingTotalResult = $salesShippingReport->getGridBlock()->getTotalResult(); + $order->persist(); + $this->objectManager->create( + \Magento\Sales\Test\TestStep\CreateShipmentStep::class, + ['order' => $order] + )->run(); + + return [ + 'initialShippingResult' => $initialShippingResult, + 'initialShippingTotalResult' => $initialShippingTotalResult, + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/SalesShippingReportEntityTest.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/SalesShippingReportEntityTest.xml new file mode 100644 index 0000000000000..3c75fe48d7a96 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestCase/SalesShippingReportEntityTest.xml @@ -0,0 +1,48 @@ + + + + + + default + full_shipment + Order Created + Year + m/d/Y 12:00 a-2 days + m/d/Y 12:00 a+2 days + Any + Yes + + + + + default + full_shipment + Order Created + Month + m/d/Y + m/d/Y + Any + No + + + + + default + full_shipment + First Invoice Created Date + Day + m/d/Y + m/d/Y + Specified + Processing + No + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/TestStep/FillShippingAddressesStep.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestStep/FillShippingAddressesStep.php new file mode 100644 index 0000000000000..3c610d6b46460 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/TestStep/FillShippingAddressesStep.php @@ -0,0 +1,98 @@ +checkoutOnepage = $checkoutOnepage; + $this->assertRate = $assertRate; + + foreach ($shippingAddresses as $address) { + $data = array_merge($clearShippingAddress, $address); + $this->shippingAddresses[] = $fixtureFactory->createByCode('address', ['data' => $data]); + } + $this->isShippingAvailable = $isShippingAvailable; + $this->shippingMethod = $shippingMethod; + } + + /** + * Fill shipping address and assert if the shipping rates is reloaded. + * + * @return void + */ + public function run() + { + foreach ($this->shippingAddresses as $key => $shippingAddress) { + $this->checkoutOnepage->getShippingBlock()->fill($shippingAddress); + $this->assertRate->processAssert( + $this->checkoutOnepage, + $this->shippingMethod, + $this->isShippingAvailable[$key] + ); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/di.xml new file mode 100644 index 0000000000000..9d3eeb3facc67 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/di.xml @@ -0,0 +1,14 @@ + + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/testcase.xml new file mode 100644 index 0000000000000..1952dcd36ecbd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/etc/testcase.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Block/Adminhtml/SitemapGrid.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Block/Adminhtml/SitemapGrid.php index 614da6ae8f90e..832104078eb00 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Block/Adminhtml/SitemapGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Block/Adminhtml/SitemapGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Handler/Sitemap/Curl.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Handler/Sitemap/Curl.php index 25b0d3748f851..c856632e66967 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Handler/Sitemap/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Handler/Sitemap/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapIndex.xml b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapIndex.xml index 16f9595b7bd7d..79031560bb712 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapNew.xml b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapNew.xml index b447f123d29eb..62c8e8161ddb8 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapNew.xml +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Page/Adminhtml/SitemapNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Repository/Sitemap.xml b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Repository/Sitemap.xml index aba108f372061..8711a4960be6d 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Repository/Sitemap.xml +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Repository/Sitemap.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/CreateSitemapEntityTest.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/CreateSitemapEntityTest.php index f820e92f9a526..77871d8e355ea 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/CreateSitemapEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/CreateSitemapEntityTest.php @@ -1,6 +1,6 @@ - test_type:extended_acceptance_test + test_type:extended_acceptance_test, severity:S1 sitemap.xml / + severity:S3 %isolation% / + severity:S3 sitemap.xml /%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/DeleteSitemapEntityTest.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/DeleteSitemapEntityTest.php index e8f24bfccc056..3523e066c8130 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/DeleteSitemapEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/DeleteSitemapEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 default diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml index cc5de2a32735d..b9b611f8a611a 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml @@ -1,13 +1,14 @@ + severity:S2 Marketing > Site Map Site Map diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Sitemap/Test/etc/curl/di.xml index 7cc682e6d7564..9492912e957a5 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/etc/curl/di.xml @@ -1,10 +1,10 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Sitemap/Test/etc/di.xml new file mode 100644 index 0000000000000..edb9dfdd9e545 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/etc/di.xml @@ -0,0 +1,54 @@ + + + + + + S2 + + + + + S3 + + + + + S3 + + + + + S2 + + + + + S3 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Block/Switcher.php b/dev/tests/functional/tests/app/Magento/Store/Test/Block/Switcher.php index 021365f49cac3..ea6b9091b9900 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Block/Switcher.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Block/Switcher.php @@ -2,7 +2,7 @@ /** * Language switcher * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Store\Test\Block; diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php index 24e63d1fe6c4f..2d1a57a488b35 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php @@ -1,6 +1,6 @@ open(); + $cmsIndex->getLogoBlock()->clickOnLogo(); + \PHPUnit_Framework_Assert::assertEquals( + $_ENV['app_frontend_url'] . $storeCode . '/', + $browser->getUrl(), + sprintf('Store code \'%s\' is not present in the url: %s', $storeCode, $browser->getUrl()) + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Store code is present in the url.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreDisabledErrorSaveMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreDisabledErrorSaveMessage.php new file mode 100644 index 0000000000000..4912ff05c94c8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreDisabledErrorSaveMessage.php @@ -0,0 +1,46 @@ +getMessagesBlock()->getErrorMessage(), + 'Wrong error message is displayed.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Store View disabled error create message is present.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php index 7242ebb35e479..9f68641bab702 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php @@ -1,6 +1,6 @@ getFormPageActions()->checkDeleteButton(), + '\'Delete\' button on StoreGroup view edit page is present when it should not.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return '\'Delete\' button on StoreGroup view edit page is absent.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php index e340b6b4876c8..63632d5fb8eac 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php @@ -1,6 +1,6 @@ getFormPageActions()->checkDeleteButton(), + '\'Delete\' button on Store view edit page is present when it should not.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return '\'Delete\' button on Store view edit page is absent.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php index 2be62c4dac8b6..bee9441fea5b6 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Store/GroupId.php b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Store/GroupId.php index 8b508168c674c..b0768bc855636 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Store/GroupId.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Store/GroupId.php @@ -1,6 +1,6 @@ params = $params; + + if (isset($data['storeGroup']) && $data['storeGroup'] instanceof StoreGroup) { + $this->storeGroup = $data['storeGroup']; + $this->data = $data['storeGroup']->getWebsiteId() . "/" . $data['storeGroup']->getName(); + return; + } + if (isset($data['dataset'])) { $storeGroup = $fixtureFactory->createByCode('storeGroup', ['dataset' => $data['dataset']]); /** @var StoreGroup $storeGroup */ @@ -39,6 +46,13 @@ public function __construct(FixtureFactory $fixtureFactory, array $params, array } $this->storeGroup = $storeGroup; $this->data = $storeGroup->getWebsiteId() . "/" . $storeGroup->getName(); + } elseif (isset($data['fixture'])) { + $this->storeGroup = $data['fixture']; + $this->data = $this->storeGroup->getWebsiteId() . "/" . $this->storeGroup->getName(); + } + + if (isset($data['value'])) { + $this->data = $data['value']; } } diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup.xml index 8c605164eec5b..35ff48de746f0 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/CategoryId.php b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/CategoryId.php index ccdc7b204894e..aa3bd13122fb6 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/CategoryId.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/CategoryId.php @@ -1,6 +1,6 @@ params = $params; - if (isset($data['dataset'])) { + if (isset($data['fixture']) || isset($data['category'])) { + $this->category = isset($data['fixture']) ? $data['fixture'] : $data['category']; + $this->data = $this->category->getName(); + } elseif (isset($data['dataset'])) { $category = $fixtureFactory->createByCode('category', ['dataset' => $data['dataset']]); /** @var Category $category */ if (!$category->getId()) { @@ -43,7 +46,7 @@ public function __construct(FixtureFactory $fixtureFactory, array $params, array } /** - * Return Category fixture + * Return Category fixture. * * @return Category */ diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/WebsiteId.php b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/WebsiteId.php index 9ad26d88d278d..07dfacff0e29e 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/WebsiteId.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/StoreGroup/WebsiteId.php @@ -1,6 +1,6 @@ params = $params; - if (isset($data['dataset'])) { + if (isset($data['fixture'])) { + $this->website = $data['fixture']; + $this->data = $this->website->getName(); + } elseif (isset($data['dataset'])) { $website = $fixtureFactory->createByCode('website', ['dataset' => $data['dataset']]); /** @var Website $website */ if (!$website->getWebsiteId()) { diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Website.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Website.xml index 74309ed39fd12..99eca6d584de3 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Website.xml +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Fixture/Website.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Store/Curl.php b/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Store/Curl.php index 5cd2898267033..642d281cd6313 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Store/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Store/Curl.php @@ -1,6 +1,6 @@ + + + + + + admin + 1 + Yes + 1 + + + + + + admin + 1 + No + 0 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml index 12ca9f5e03a20..1958f21740bc9 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml @@ -1,7 +1,7 @@ @@ -44,6 +44,7 @@ de%isolation% Enabled + custom_new_group @@ -52,5 +53,32 @@ store_%isolation% Enabled + + + + custom + + Custom_Store_%isolation% + code_%isolation% + Enabled + + + + + store_group_new_1 + + New_Store_%isolation% + store_group_new_1_%isolation% + Enabled + + + + + store_group_new_2 + + New_Store_2_%isolation% + store_group_new_2_%isolation% + Enabled + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml index f07c79a8967d5..106b72528f5a5 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml @@ -1,7 +1,7 @@ @@ -37,5 +37,25 @@ default_category + + + + website_new_1 + + New_Store_Group_%isolation% + + default_category + + + + + + website_new_2 + + New_Store_Group_2_%isolation% + + root_category + + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml index 5c2ec69efca98..fbd1187585236 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml @@ -1,7 +1,7 @@ @@ -29,5 +29,15 @@ Web_Site_%isolation% code_%isolation% + + + New_Website_%isolation% + new_%isolation% + + + + New_Website_2_%isolation% + new2_%isolation% + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.php new file mode 100644 index 0000000000000..021cc249c7ea0 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.php @@ -0,0 +1,82 @@ +stepFactory = $stepFactory; + } + + /** + * Set config and log out from Admin. + * + * @param string $configData + * @return void + */ + public function test($configData) + { + $this->configData = $configData; + $this->stepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + $this->stepFactory->create( + \Magento\User\Test\TestStep\LogoutUserOnBackendStep::class, + ['configData' => $this->configData] + )->run(); + } + + /** + * Reset config settings to default. + * + * @return void + */ + public function tearDown() + { + $this->stepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.xml new file mode 100644 index 0000000000000..6496f4a867333 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.xml @@ -0,0 +1,18 @@ + + + + + + add_store_code_to_urls + default + default + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreEntityTest.php index 804111c497cca..ab5ae8fbab2c0 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreEntityTest.php @@ -1,6 +1,6 @@ + severity:S1 default store_name_%isolation% storecode_%isolation% Enabled - - + severity:S3 default store_name_%isolation% storecode_%isolation% Disabled - - + severity:S1 custom store_name_%isolation% storecode_%isolation% @@ -41,7 +40,7 @@ - test_type:acceptance_test, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test, severity:S0 default DE_%isolation% de_%isolation% @@ -51,5 +50,18 @@ + + custom_store + + + + + + custom_new_group + store_name_%isolation% + storecode_%isolation% + Disabled + + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.php index 5d638d781d173..f5075ecc81815 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.php @@ -1,6 +1,6 @@ + severity:S1 main_website store_name_%isolation% default_category - + severity:S1 custom_website store_name_%isolation% root_category @@ -25,5 +26,11 @@ + + custom_new_group + + + + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateWebsiteEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateWebsiteEntityTest.php index 766e030b3f618..92683e7308a6b 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateWebsiteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateWebsiteEntityTest.php @@ -1,6 +1,6 @@ + severity:S1 website_%isolation% code_%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php index cbe261fe750a8..6febf85a8ab73 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 custom Yes @@ -16,10 +17,10 @@ + severity:S2, stable:no custom No - diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php index e7ba27b44c1a8..c7f3a0853fa45 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteStoreGroupEntityTest.php @@ -1,6 +1,6 @@ + severity:S3, stable:no custom Yes @@ -15,6 +16,7 @@ + severity:S3, stable:no custom No diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php index 5d4af70cb03e3..02a0accf42315 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/DeleteWebsiteEntityTest.php @@ -1,6 +1,6 @@ + severity:S3 custom_website Yes @@ -15,6 +16,7 @@ + severity:S3 custom_website No diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.php new file mode 100644 index 0000000000000..a21dba4282d16 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.php @@ -0,0 +1,107 @@ + All Stores + * 3. Open store view SVB from grid + * 4. Change store group setting from STB to STA + * 5. Save store entity + * 6. Perform all assertions + * + * @group Store_Management + * @ZephyrId MAGETWO-54026 + */ +class MoveStoreToOtherGroupSameWebsiteTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * Page StoreIndex + * + * @var StoreIndex + */ + protected $storeIndex; + + /** + * Page EditStore + * + * @var EditStore + */ + protected $editStore; + + /** + * Preparing pages for test + * + * @param StoreIndex $storeIndex + * @param EditStore $editStore + * @return void + */ + public function __inject(StoreIndex $storeIndex, EditStore $editStore) + { + $this->storeIndex = $storeIndex; + $this->editStore = $editStore; + } + + /** + * Move store view to another store group within a website + * + * @param FixtureFactory $fixtureFactory + * @param Store $storeInitialA + * @param Store $storeInitialB + * @return array + */ + public function test(FixtureFactory $fixtureFactory, Store $storeInitialA, Store $storeInitialB) + { + // Prepare data for constraints + $store = $fixtureFactory->createByCode( + 'store', + [ + 'data' => [ + 'name' => $storeInitialB->getName(), + 'code' => $storeInitialB->getCode(), + 'is_active' => $storeInitialB->getIsActive(), + 'group_id' => [ + 'storeGroup' => $storeInitialA->getDataFieldConfig('group_id')['source']->getStoreGroup() + ], + ], + ] + ); + + // Preconditions + $storeInitialA->persist(); + $storeInitialB->persist(); + + // Steps + $this->storeIndex->open(); + $this->storeIndex->getStoreGrid()->searchAndOpenStore($storeInitialB); + $this->editStore->getStoreForm()->selectStore($storeInitialA->getGroupId()); + $this->editStore->getFormPageActions()->save(); + + return ['store' => $store]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.xml new file mode 100644 index 0000000000000..10976eb380b1c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.xml @@ -0,0 +1,20 @@ + + + + + + custom_group_custom_store + custom_group_custom_store + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.php index 38250d958bc10..cb46f43d4e7bc 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 custom default storename_updated%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.php index 7e9143a5c91df..01a90807395b3 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 custom main_website store_name_updated_%isolation% default_category - + severity:S2 custom custom_website store_name_updated_%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateWebsiteEntityTest.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateWebsiteEntityTest.php index b187f05856670..9b611b4594271 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateWebsiteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateWebsiteEntityTest.php @@ -1,6 +1,6 @@ + severity:S2 custom_website website_upd%isolation% code_upd%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Store/Test/etc/curl/di.xml index 24c4b0b4b519b..6e5d977c0b7ab 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Store/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Store/Test/etc/di.xml new file mode 100644 index 0000000000000..3c311bfad8628 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Store/Test/etc/di.xml @@ -0,0 +1,124 @@ + + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S2 + + + + + S3 + + + + + S1 + + + + + S3 + + + + + S3 + + + + + S1 + + + + + S2 + + + + + S3 + + + + + S3 + + + + + S2 + + + + + S2 + + + + + S1 + + + + + S1 + + + + + S2 + + + + + S3 + + + + + S1 + + + + + S3 + + + + + S3 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php index 0d0889db60d54..b2087f4c76c1b 100644 --- a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php +++ b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php new file mode 100644 index 0000000000000..35f460c5ff937 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ListProduct.php @@ -0,0 +1,30 @@ +productItem, $product->getName()); + + return $this->blockFactory->create( + \Magento\Swatches\Test\Block\Product\ProductList\ProductItem::class, + ['element' => $this->_rootElement->find($locator, Locator::SELECTOR_XPATH)] + ); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php new file mode 100755 index 0000000000000..3a123d4fbe848 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ProductList/ProductItem.php @@ -0,0 +1,73 @@ +getCheckoutData(); + $options = $checkoutData['options']['configurable_options']; + $confAttrData = $product->getDataFieldConfig('configurable_attributes_data'); + $confAttrSource = $confAttrData['source']; + $attributes = $confAttrSource->getAttributes(); + + foreach ($options as $option) { + if (!isset($attributes[$option['title']]) + || stripos($attributes[$option['title']]->getFrontendInput(), "swatch") === false + ) { + continue; + } + $availableOptions = $attributes[$option['title']]->getOptions(); + $optionKey = str_replace('option_key_', '', $option['value']); + if (!isset($availableOptions[$optionKey])) { + continue; + } + $optionForSelect = $availableOptions[$optionKey]; + $this->clickOnSwatch($optionForSelect['id']); + } + } + + /** + * Click on swatch. + * + * @param $optionId + */ + private function clickOnSwatch($optionId) + { + $selector = sprintf($this->swatchSelector, $optionId); + $this->_rootElement->find($selector, Locator::SELECTOR_CSS)->click(); + } + + /** + * @inheritdoc + */ + public function clickAddToCart() + { + $this->_rootElement->hover(); + parent::clickAddToCart(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php new file mode 100644 index 0000000000000..c07ec2f8390b7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php @@ -0,0 +1,45 @@ +getCheckoutData(); + $availableAttributes = $product->getConfigurableAttributesData(); + $attributesData = $availableAttributes['attributes_data']; + $formData = []; + foreach ($checkoutData['options']['configurable_options'] as $item) { + $selector = sprintf($this->swatchAttributeSelector, $attributesData[$item['title']]['attribute_code']); + $this->waitForElementVisible($selector); + $selected = $this->_rootElement->find($selector)->getText(); + $formData[$item['title']] = $selected; + } + + return $formData; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchConfigurableProductPage.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchConfigurableProductPage.php new file mode 100644 index 0000000000000..67c2c18ed8544 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchConfigurableProductPage.php @@ -0,0 +1,92 @@ +product = $product; + $this->productView = $catalogProductView->getProductViewWithSwatchesBlock(); + + // we need this line for waiti until page will be fully loaded + $this->productView->getSelectedSwatchOptions($this->product); + $errors = $this->verify(); + \PHPUnit_Framework_Assert::assertEmpty( + $errors, + "\nFound the following errors:\n" . implode(" \n", $errors) + ); + } + + /** + * Verify product on product view page. + * + * @return array + */ + protected function verify() + { + $errors = parent::verify(); + $errors[] = $this->verifySwatches(); + + return array_filter($errors); + } + + /** + * Verify selected swatches on product view page. + * + * @return array + */ + protected function verifySwatches() + { + $actualData = $this->productView->getSelectedSwatchOptions($this->product); + $expectedData = $this->convertCheckoutData($this->product); + $this->verifyData($expectedData, $actualData); + } + + /** + * Get swatch attributes formatter to attributes comparison. + * + * @param FixtureInterface $product + * @return array + */ + public function convertCheckoutData(FixtureInterface $product) + { + $out = []; + $checkoutData = $product->getCheckoutData(); + $availableAttributes = $product->getConfigurableAttributesData(); + $attributesData = $availableAttributes['attributes_data']; + foreach ($checkoutData['options']['configurable_options'] as $item) { + $out[$item['title']] = $attributesData[$item['title']]['options'][$item['value']]['label']; + } + + return $out; + } + + /** + * Return string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Swatch attributes displayed as expected on product page'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/Cart/Item.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/Cart/Item.php new file mode 100644 index 0000000000000..13564b5c56f2c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/Cart/Item.php @@ -0,0 +1,17 @@ + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml new file mode 100644 index 0000000000000..29ff66dc2cbea --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Fixture/SwatchProductAttribute.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php new file mode 100644 index 0000000000000..2bc6d35262ca2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/Curl.php @@ -0,0 +1,49 @@ +mappingData['frontend_input'] = [ + 'Text Swatch' => 'swatch_text', + ]; + } + + /** + * Re-map options from default options structure to swatches structure, + * as swatches was initially created with name convention differ from other attributes. + * + * @param array $data + * @return array + */ + protected function changeStructureOfTheData(array $data) + { + $data = parent::changeStructureOfTheData($data); + $data['optiontext'] = $data['option']; + $data['swatchtext'] = [ + 'value' => $data['option']['value'] + ]; + unset($data['option']); + return $data; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php new file mode 100644 index 0000000000000..a4c28796a08db --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Handler/SwatchProductAttribute/SwatchProductAttributeInterface.php @@ -0,0 +1,17 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Product/CatalogProductView.xml new file mode 100644 index 0000000000000..7329424770bd9 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Product/CatalogProductView.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml new file mode 100644 index 0000000000000..ce27580efd193 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml @@ -0,0 +1,83 @@ + + + + + + Test configurable product with color and size %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + text_swatch + + + In Stock + + + default_subcategory + + + + default + + + + custom_attribute_set + + + 40 + price_40 + + + two_text_swatches + + + + Test configurable product with color and size %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + text_swatch_with_dropdown + + + In Stock + + + default_subcategory + + + + default + + + + custom_attribute_set + + + 40 + price_40 + + + swatches_with_dropdown + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml new file mode 100644 index 0000000000000..183890a130f14 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml @@ -0,0 +1,51 @@ + + + + + + + + + attribute_key_0 + option_key_1 + + + attribute_key_1 + option_key_2 + + + + 1 + + 42 + 1 + 47 + + + + + + + attribute_key_0 + option_key_1 + + + attribute_key_1 + option_key_1 + + + + 1 + + 42 + 1 + 47 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml new file mode 100644 index 0000000000000..494a4f56b7703 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -0,0 +1,151 @@ + + + + + + + + + + 12.00 + Yes + + + 20.00 + Yes + + + 18.00 + Yes + + + + + + + 42.00 + Yes + + + 40.00 + Yes + + + 48.00 + Yes + + + + + + swatchesProductAttribute::attribute_type_text_swatch + swatchesProductAttribute::attribute_type_text_swatch + + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + + + + + + + 12.00 + Yes + + + 20.00 + Yes + + + 18.00 + Yes + + + + + + + 42.00 + Yes + + + 40.00 + Yes + + + + + + swatchesProductAttribute::attribute_type_text_swatch + catalogProductAttribute::size + + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml new file mode 100644 index 0000000000000..dfd63bbf19574 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml @@ -0,0 +1,35 @@ + + + + + + sw_color%isolation% + Text Swatch + Text Swatch + + + No + R + R + + + No + G + G + + + No + B + B + + + Global + Yes + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.php new file mode 100644 index 0000000000000..a0dff493ce5da --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.php @@ -0,0 +1,83 @@ +testStepFactory = $testStepFactory; + $this->categoryView = $categoryView; + } + + /** + * Runs add configurable product with swatches attributes test. + * + * @param ConfigurableProduct $product + * @param bool $addToCart + * @return array + */ + public function test(ConfigurableProduct $product, $addToCart) + { + $product->persist(); + $cart = $this->testStepFactory->create( + \Magento\Swatches\Test\TestStep\AddProductToCartFromCatalogCategoryPageStep::class, + [ + 'product' => $product + ] + )->run()['cart']; + if ($addToCart) { + $this->categoryView->getMessagesBlock()->waitSuccessMessage(); + } + + return ['cart' => $cart]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.xml new file mode 100644 index 0000000000000..32ee63cf57f33 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.xml @@ -0,0 +1,23 @@ + + + + + + addOptions + product_with_text_swatch + true + + + + addOptions + product_with_text_swatch_and_size + false + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php new file mode 100644 index 0000000000000..57104ad2baea6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php @@ -0,0 +1,96 @@ +fixtureFactory = $fixtureFactory; + $this->cmsIndex = $cmsIndex; + $this->categoryView = $categoryView; + $this->product = $product; + } + + /** + * Update configurable product. + * + * @return array + */ + public function run() + { + $categoryName = $this->product->getCategoryIds()[0]; + $this->cmsIndex->open(); + $this->cmsIndex->getTopmenu()->selectCategoryByName($categoryName); + /** @var \Magento\Swatches\Test\Block\Product\ListProduct $productsList */ + $productsList = $this->categoryView->getListSwatchesProductBlock(); + /** @var ProductItem $productItemBlock */ + $productItemBlock = $productsList->getProductItem($this->product); + $productItemBlock->fillData($this->product); + $productItemBlock->clickAddToCart(); + $cart = [ + 'data' => [ + 'items' => [ + 'products' => [$this->product] + ] + ] + ]; + + return [ + 'cart' => $this->fixtureFactory->createByCode('cart', $cart) + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml new file mode 100644 index 0000000000000..b0d43eb4cce2f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/etc/curl/di.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/Form.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/Form.php index 3d3bfba4c9bf9..ac3d05db56d3b 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/Form.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/Form.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php index 3c719ad2d9733..09bb5bc7c8f8f 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/TaxRate.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/TaxRate.php index c5fcecf020e6c..57ee92d2d7f3a 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/TaxRate.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/TaxRate.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Grid.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Grid.php index c5466e7697693..41de5889df94f 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRate.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRate.xml index ca18253f16e60..ac6e7903114f0 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRate.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRate.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule.xml index 0ac799c651a17..d355f885b6fea 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule/TaxClass.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule/TaxClass.php index 538a9d6b48730..67c43646fde03 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule/TaxClass.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Fixture/TaxRule/TaxClass.php @@ -1,6 +1,6 @@ taxRuleGridUrl = $_ENV['app_backend_url'] . 'tax/rule/index/'; - $curl = $this->_getCurl($this->taxRuleGridUrl); + $curl = $this->getCurl($this->taxRuleGridUrl); $response = $curl->read(); - $this->_removeTaxRules($response); + $this->removeTaxRules($response); $curl->close(); return $response; } diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/TaxClass/Curl.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/TaxClass/Curl.php index 1298d8a62ddce..03409154fbcfd 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/TaxClass/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Handler/TaxClass/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRateNew.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRateNew.xml index 9b3b5a2efd3bb..1c227d2ce54e3 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRateNew.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRateNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleIndex.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleIndex.xml index 47b450121cac9..f12c2189e7474 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleNew.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleNew.xml index d8443e65da6f8..bb9497a4a9811 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleNew.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Page/Adminhtml/TaxRuleNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/ConfigData.xml index 33ecac40bfe3a..c0b65e9a4a44c 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -164,7 +164,7 @@ tax 1 - Before Discount + After Discount 0 @@ -541,6 +541,15 @@ + + + tax + 1 + After Discount + 1 + + + tax @@ -580,6 +589,15 @@ + + + tax + 1 + After Discount + 1 + + + tax @@ -619,6 +637,15 @@ + + + tax + 1 + After Discount + 1 + + + tax @@ -697,6 +724,15 @@ + + + tax + 1 + After Discount + 1 + + + tax @@ -852,5 +888,23 @@ 1 + + + + tax + 1 + Yes + 1 + + + + + + tax + 1 + No + 0 + + diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml index 061bc05c07891..7cc6cbcea4c75 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml index acd8ef1d8cc9d..7f951d3fb4187 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRule.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRule.xml index 3729c0f7db4e0..c4ddc4b02c1ce 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRule.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRule.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/ApplyTaxBasedOnVatIdTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/ApplyTaxBasedOnVatIdTest.php index b35c566fd9b98..1d735eb9666cc 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/ApplyTaxBasedOnVatIdTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/ApplyTaxBasedOnVatIdTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRateEntityTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRateEntityTest.php index f13cfc8d42793..0d45b857ef744 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRateEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRateEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRuleEntityTest.php index 9cfa401510bc1..bac314df120f8 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/CreateTaxRuleEntityTest.php @@ -1,6 +1,6 @@ @@ -19,6 +19,7 @@ + stable:no TaxIdentifier%isolation% US-CA-Rate_1 US-NY-Rate_1 @@ -47,6 +48,7 @@ + stable:no TaxIdentifier%isolation% withZipRange US-CA-Rate_1 @@ -60,7 +62,7 @@ - test_type:acceptance_test, stable:no, test_type:extended_acceptance_test + test_type:acceptance_test, test_type:extended_acceptance_test TaxIdentifier%isolation% US-CA-*-Rate 1 us_ny_rate_8_1 diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest.php index 567e4860df12b..2a98b8f350a1e 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRuleEntityTest.php index 5553738b21463..ac8f8d44fe222 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRuleEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml index 1c35597b31dd8..43d102e13c41b 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxCalculationTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxCalculationTest.php index 14ef3cc293d92..44c0fa456fa52 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxCalculationTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxCalculationTest.php @@ -1,6 +1,6 @@ + to_maintain:yes Simple product tier price with sales rule, customer tax equals store tax and catalog price including tax shipping_tax_class_taxable_goods, row_cat_incl_ship_excl_after_disc_on_excl, display_excluding_including_tax catalogProductSimple::simple_with_tier_price_and_category @@ -37,6 +38,7 @@ + to_maintain:yes Simple product special price with sales rule, customer tax less than store tax and catalog price including tax shipping_tax_class_taxable_goods, row_cat_incl_ship_excl_before_disc_on_incl, display_excluding_including_tax catalogProductSimple::product_with_special_price_and_category @@ -66,6 +68,7 @@ + to_maintain:yes Simple product tier price with sales rule, customer tax less than store tax and catalog price including tax shipping_tax_class_taxable_goods, unit_cat_incl_ship_incl_before_disc_on_incl, display_excluding_including_tax catalogProductSimple::simple_with_tier_price_and_category @@ -95,6 +98,7 @@ + to_maintain:yes Simple product special price with sales rule, customer tax equals store tax and catalog price excluding tax shipping_tax_class_taxable_goods, total_cat_excl_ship_incl_before_disc_on_incl, display_excluding_including_tax catalogProductSimple::product_with_special_price_and_category @@ -124,6 +128,7 @@ + to_maintain:yes Simple product tier price with sales rule, customer tax greater than store tax and catalog price excluding tax shipping_tax_class_taxable_goods, total_cat_excl_ship_incl_after_disc_on_incl, display_excluding_including_tax catalogProductSimple::simple_with_tier_price_and_category @@ -153,6 +158,7 @@ + to_maintain:yes Simple product special price with sales rule, customer tax greater than store tax and catalog price excluding tax shipping_tax_class_taxable_goods, unit_cat_excl_ship_incl_after_disc_on_excl, display_excluding_including_tax catalogProductSimple::product_with_special_price_and_category diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxWithCrossBorderTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxWithCrossBorderTest.php index 9517ee063ce67..38ba6df836a95 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxWithCrossBorderTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/TaxWithCrossBorderTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRateEntityTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRateEntityTest.php index ff54451529aab..8fe33b82ebcfe 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRateEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRateEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRuleEntityTest.php index bef2ede5733cd..e904968e349f5 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/UpdateTaxRuleEntityTest.php @@ -1,6 +1,6 @@ @@ -48,6 +48,7 @@ + stable:no tax_rule_with_custom_tax_classes United States Idaho diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php index 37113ef0cc225..cbb54838f6bcd 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestStep/CreateTaxRuleStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/di.xml index 0ee0e233fdea7..e1900ce8d7ce6 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/testcase.xml index a9d4f0afe64e4..72bd680f948a6 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/testcase.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/webapi/di.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/webapi/di.xml index e5528c9126651..722ef292a555b 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/webapi/di.xml +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/webapi/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Breadcrumbs.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Breadcrumbs.php index 8534806bedd25..f82ba822c9147 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Breadcrumbs.php +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Breadcrumbs.php @@ -1,6 +1,6 @@ _rootElement->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Title.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Title.php index ecae74663f66c..c8c4969d0350e 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Title.php +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Html/Title.php @@ -1,6 +1,6 @@ click(); } + /** + * Hover on category from top menu by name. + * + * @param string $categoryName + * @return void + */ + public function hoverCategoryByName($categoryName) + { + $rootElement = $this->_rootElement; + $category = $this->waitLoadTopMenu($categoryName); + if ($category[1]) { + $rootElement->waitUntil( + function () use ($category) { + return $category[0]->isVisible() ? true : null; + } + ); + } + $category[0]->hover(); + } + /** * Check is visible category in top menu by name * diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php index 1309ff6904a2d..f79a4542bb631 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Block/Links.php @@ -1,6 +1,6 @@ waitForElementVisible($this->welcomeMessage); } + /** + * Get text of the welcome message. + * + * @return string + */ + public function getWelcomeText() + { + $this->waitForElementVisible($this->welcomeMessage); + return $this->_rootElement->find($this->welcomeMessage)->getText(); + } + /** * Verify if authorization link is present or not. * diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/Page/CheckoutOnepageSuccess.xml b/dev/tests/functional/tests/app/Magento/Theme/Test/Page/CheckoutOnepageSuccess.xml index 12b0b0776f1a0..d98d3165d8628 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/Page/CheckoutOnepageSuccess.xml +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/Page/CheckoutOnepageSuccess.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml index 2b69cc3b338e7..4c8228e0d6fdf 100644 --- a/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractContainer.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractContainer.php index 9331d9ea4c62a..f34ad367cf42e 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractContainer.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/AbstractContainer.php @@ -1,6 +1,6 @@ [field => [attribute_name => attribute_value, ..], ..], ..] * where container name can be empty if a field is not assigned to any container. diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php index eae09d72a47b9..3c3a1db358912 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/DataGrid.php @@ -1,6 +1,6 @@ _rootElement->find($this->appliedFiltersList); + $chipsHolder = $this->getGridHeaderElement()->find($this->appliedFiltersList); if ($chipsHolder->isVisible()) { parent::resetFilter(); } @@ -165,7 +183,7 @@ public function resetFilter() */ protected function waitFilterToLoad() { - $this->getTemplateBlock()->waitForElementNotVisible($this->loader); + $this->getTemplateBlock()->waitLoader(); $browser = $this->_rootElement; $selector = $this->filterButton . ', ' . $this->resetButton; $browser->waitUntil( @@ -322,14 +340,17 @@ public function selectMassAction($massActionSelection) public function selectAction($action) { $actionType = is_array($action) ? key($action) : $action; - $this->_rootElement->find($this->actionButton)->click(); - $this->_rootElement - ->find(sprintf($this->actionList, $actionType), Locator::SELECTOR_XPATH) - ->click(); + $this->getGridHeaderElement()->find($this->actionButton)->click(); + $toggle = $this->getGridHeaderElement()->find(sprintf($this->actionList, $actionType), Locator::SELECTOR_XPATH); + $toggle->hover(); + if ($toggle->isVisible() === false) { + $this->getGridHeaderElement()->find($this->actionButton)->click(); + } + $toggle->click(); if (is_array($action)) { - $this->_rootElement - ->find(sprintf($this->actionList, end($action)), Locator::SELECTOR_XPATH) - ->click(); + $locator = sprintf($this->actionList, end($action)); + $this->getGridHeaderElement()->find($locator, Locator::SELECTOR_XPATH)->hover(); + $this->getGridHeaderElement()->find($locator, Locator::SELECTOR_XPATH)->click(); } } @@ -347,7 +368,7 @@ public function selectItems(array $items, $isSortable = true) $this->sortGridByField('ID'); } foreach ($items as $item) { - $this->_rootElement->find($this->currentPage)->setValue(''); + $this->_rootElement->find($this->currentPage, Locator::SELECTOR_XPATH)->setValue(''); $this->waitLoader(); $selectItem = $this->getRow($item)->find($this->selectItem); do { @@ -382,13 +403,17 @@ public function sortGridByField($field, $sort = "desc") } /** + * Sort grid by column. + * * @param string $columnLabel + * @return void */ public function sortByColumn($columnLabel) { $this->waitLoader(); $this->getTemplateBlock()->waitForElementNotVisible($this->loader); $this->_rootElement->find(sprintf($this->columnHeader, $columnLabel), Locator::SELECTOR_XPATH)->click(); + $this->waitLoader(); } /** @@ -427,7 +452,11 @@ public function getColumnValue($id, $headerLabel) { $this->waitLoader(); $this->getTemplateBlock()->waitForElementNotVisible($this->loader); - $selector = sprintf($this->rowById, $id) . sprintf($this->cellByHeader, $headerLabel); + $columnNumber = count( + $this->_rootElement->getElements(sprintf($this->columnNumber, $headerLabel), Locator::SELECTOR_XPATH) + ); + $selector = sprintf($this->rowById, $id) . sprintf($this->cellByHeader, $columnNumber); + return $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->getText(); } @@ -463,4 +492,14 @@ public function getRowsData(array $columns) return $data; } + + /** + * Returns admin data grid header element. + * + * @return \Magento\Mtf\Client\ElementInterface + */ + private function getGridHeaderElement() + { + return $this->_rootElement->find($this->gridHeader, Locator::SELECTOR_XPATH); + } } diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php index 6a5919b8cb1cf..713bb22d53f3c 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/FormSections.php @@ -1,55 +1,31 @@ getContainerElement($sectionName); - return $container->find($this->sectionTitle); - } - - /** - * Opens the section. + * Expand section by its name. * * @param string $sectionName * @return $this */ public function openSection($sectionName) { - if ($this->isCollapsible($sectionName) && !$this->isCollapsed($sectionName)) { - $this->getSectionTitleElement($sectionName)->click(); - } else { - //Scroll to the top of the page so that the page actions header does not overlap any controls - $this->browser->find($this->header)->hover(); + $section = $this->getContainerElement($sectionName)->find($this->collapsedSection); + if ($section->isVisible()) { + $section->click(); } + return $this; } /** - * Checks if the section is collapsible on the form. + * Check if section is collapsible. * + * @deprecated * @param string $sectionName * @return bool */ public function isCollapsible($sectionName) { - $title = $this->getSectionTitleElement($sectionName); - if (!$title->isVisible()) { - return false; - }; - return $title->find('parent::' . $this->collapsible, Locator::SELECTOR_XPATH)->isVisible(); - } + $section = $this->getContainerElement($sectionName); - /** - * Check if collapsible section is opened. - * - * @param string $sectionName - * @return bool - */ - private function isCollapsed($sectionName) - { - return $this->getContainerElement($sectionName)->find($this->opened)->isVisible(); + if ($section->find($this->collapsedSection)->isVisible()) { + return true; + } elseif ($section->find($this->expandedSection)->isVisible()) { + return true; + } else { + return false; + } } /** @@ -151,11 +108,12 @@ public function getRequireNoticeFields(InjectableFixture $product) /** * Check if section is visible. * + * @deprecated * @param string $sectionName * @return bool */ public function isSectionVisible($sectionName) { - return ($this->isCollapsible($sectionName) && !$this->isCollapsed($sectionName)); + return !$this->getContainerElement($sectionName)->find($this->collapsedSection)->isVisible(); } } diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Modal.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Modal.php index e703369856834..bdff2aeb96283 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Modal.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Modal.php @@ -1,6 +1,6 @@ _rootElement->find($this->acceptButtonSelector)->click(); } + /** + * Press OK on a warning popup. + * + * @return void + */ + public function acceptWarning() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->acceptWarningSelector)->click(); + $this->waitForElementNotVisible($this->loadingMask); + } + + /** + * Press Cancel on a warning popup. + * + * @return void + */ + public function dismissWarning() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->dismissWarningSelector)->click(); + } + /** * Press Cancel on an alert, confirm, prompt a dialog. * diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php index f0aafd5250fd4..5c002d3942ae4 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Block/Adminhtml/Section.php @@ -1,6 +1,6 @@ waitForElementVisible($this->successMessage, Locator::SELECTOR_CSS); + } + + /** + * Get all success messages which are present on the page. + * + * @return array + */ + public function getSuccessMessages() + { + $this->waitForElementVisible($this->successMessage); + $elements = $this->_rootElement->getElements($this->successMessage); + + $messages = []; + foreach ($elements as $element) { + $messages[] = $element->getText(); + } + + return $messages; + } + + /** + * Get all notice messages which are present on the page. + * + * @return array + */ + public function getNoticeMessages() + { + $this->waitForElementVisible($this->noticeMessage); + $elements = $this->_rootElement->getElements($this->noticeMessage); + + $messages = []; + foreach ($elements as $element) { + $messages[] = $element->getText(); + } + + return $messages; + } + + /** + * Get last success message which is present on the page. + * + * @return string + */ + public function getSuccessMessage() + { + $this->waitForElementVisible($this->successMessage); + + return $this->_rootElement->find($this->lastSuccessMessage)->getText(); + } + + /** + * Wait for element is visible in the page. + * + * @param string $selector + * @param string $strategy + * @return bool|null + */ + public function waitForElementVisible($selector, $strategy = Locator::SELECTOR_CSS) + { + $browser = $this->browser; + return $browser->waitUntil( + function () use ($browser, $selector, $strategy) { + $message = $browser->find($selector, $strategy); + return $message->isVisible() ? true : null; + } + ); + } + + /** + * Get all error message which is present on the page. + * + * @return string + */ + public function getErrorMessage() + { + return $this->_rootElement + ->find($this->errorMessage, Locator::SELECTOR_CSS) + ->getText(); + } + + /** + * Get notice message which is present on the page. + * + * @return string + */ + public function getNoticeMessage() + { + $this->waitForElementVisible($this->noticeMessage); + return $this->_rootElement->find($this->noticeMessage)->getText(); + } + + /** + * Get warning message which is present on the page. + * + * @return string + */ + public function getWarningMessage() + { + $this->waitForElementVisible($this->warningMessage); + return $this->_rootElement->find($this->warningMessage)->getText(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php index 49f861fd40e49..3b64372100ab5 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php @@ -1,6 +1,6 @@ + + + + + S2 + + + + + S2 + + + + + S2 + + + diff --git a/dev/tests/functional/tests/app/Magento/Ups/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Ups/Test/Repository/ConfigData.xml index 1de1a166d7482..37dccb9d27cf1 100644 --- a/dev/tests/functional/tests/app/Magento/Ups/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Ups/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Ups/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Ups/Test/TestCase/OnePageCheckoutTest.xml index b27bc81d28660..647e38b2d22f1 100644 --- a/dev/tests/functional/tests/app/Magento/Ups/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Ups/Test/TestCase/OnePageCheckoutTest.xml @@ -1,7 +1,7 @@ @@ -20,7 +20,7 @@ UPS Ground checkmo checkmo, ups, shipping_origin_US_CA - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 @@ -39,7 +39,7 @@ UPS Worldwide Expedited checkmo checkmo, ups, shipping_origin_US_CA - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Grid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Grid.php index 54de30e734d90..df671f388a025 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Grid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Grid.php @@ -1,6 +1,6 @@ [ 'selector' => 'input[name="target_path"]', ], + 'store_id' => [ + 'selector' => 'select[name="store_id"]', + 'input' => 'select', + ], + 'redirect_type' => [ + 'selector' => 'select[name="redirect_type"]', + 'input' => 'select', + ], ]; } diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Tree.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Tree.php index 7f7f3dc18e7c3..a128c36bd8d24 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Tree.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Tree.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Product/Grid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Product/Grid.php index 70274c72e610d..e9c2e6c27a0a4 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Product/Grid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Product/Grid.php @@ -1,6 +1,6 @@ open(); + $cmsIndex->getStoreSwitcherBlock()->selectStoreView($storeView->getName()); + $cmsIndex->getTopmenu()->hoverCategoryByName($parentCategory->getName()); + $cmsIndex->getTopmenu()->selectCategoryByName( + $childCategory->getName() + ); + $actualUrl = strtolower($parentCategory->getUrlKey() . '/' . $categoryUpdates->getUrlKey()); + + \PHPUnit_Framework_Assert::assertContains( + $actualUrl, + $browser->getUrl(), + "Category URL is not correct." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Category URL is correct.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php index 10e5acf596137..425f0b9557d3e 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php @@ -1,6 +1,6 @@ getDataFieldConfig('category_ids')['source']->getCategories()[0]; + $catalogCategoryIndex->open(); + $catalogCategoryIndex->getTreeCategories()->selectCategory($category); + $catalogCategoryEdit->getFormPageActions()->delete(); + $catalogCategoryEdit->getModalBlock()->acceptAlert(); + + $assertCategoryUrlRewrite->processAssert($urlRewriteIndex, $category); + $assertUrlRewrite->processAssert($urlRewriteIndex, $urlRewrite); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'URL rewrites are deleted.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php index b94e716ceac64..573c68830cd1c 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php @@ -1,40 +1,181 @@ urlRewriteIndex = $urlRewriteIndex; + $this->webApi = $webApi; + $urlRewriteIndex->open(); - $filter = ['target_path' => strtolower($category->getUrlKey())]; + $categoryId = $this->getCategoryId($category, $childCategory); + $nestingPath = $this->getNestingPath($category, $nestingLevel); + + $filter = [ + 'request_path' => $nestingPath, + 'target_path' => 'catalog/category/view/id/' . $categoryId, + 'redirect_type' => self::REDIRECT_TYPE_NO + ]; + if ($parentCategory && $childCategory) { + $filter['request_path'] = + strtolower($parentCategory->getUrlKey() . '/' . $childCategory->getUrlKey() . '.html'); + } + $this->rowVisibleAssertion($filter); + + if ($redirectType != self::REDIRECT_TYPE_NO) { + if ($parentCategory && $childCategory) { + $urlPath = strtolower($parentCategory->getUrlKey() . '/' . $childCategory->getUrlKey() . '.html'); + $filter = [ + 'request_path' => $nestingPath, + 'target_path' => $urlPath, + 'redirect_type' => $redirectType + ]; + } else { + $filter = [$filterByPath => strtolower($category->getUrlKey())]; + } + $this->rowVisibleAssertion($filter); + } + } + + /** + * Get category id. + * + * @param Category $category + * @param Category|null $childCategory + * @return int + */ + private function getCategoryId(Category $category, Category $childCategory = null) + { + return ($childCategory ? $childCategory->getId() : $category->getId()) + ? $category->getId() + : $this->retrieveCategory($category)['id']; + } + + /** + * Assert that url rewrite category in grid. + * + * @param array $filter + * @return void + */ + private function rowVisibleAssertion(array $filter) + { + $filterRow = implode(', ', $filter); \PHPUnit_Framework_Assert::assertTrue( - $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), - 'URL Rewrite with request path "' . $category->getUrlKey() . '" is absent in grid.' + $this->urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), + 'URL Rewrite with request path "' . $filterRow . '" is absent in grid.' ); } /** - * URL rewrite category present in grid + * Return nesting url path. + * + * @param Category $category + * @param int $nestingLevel + * @return string + */ + private function getNestingPath(Category $category, $nestingLevel) + { + if ($nestingLevel === null) { + return strtolower($category->getUrlKey() . '.html'); + } + $filterByRequestPathCondition = []; + for ($nestingIterator = 0; $nestingIterator < $nestingLevel; $nestingIterator++) { + $filterByRequestPathCondition[] = $category->getUrlKey(); + $category = $category->getDataFieldConfig('parent_id')['source']->getParentCategory(); + } + + return strtolower(implode('/', array_reverse($filterByRequestPathCondition)) . '.html'); + } + + /** + * Retrieve category. + * + * @param Category $category + * @return array + */ + private function retrieveCategory(Category $category) + { + $childrenIds = explode(',', $this->getResponse($category->getData('parent_id'))['children']); + while ($id = array_pop($childrenIds)) { + $retrieveCategory = $this->getResponse($id); + if ($retrieveCategory['name'] == $category->getData('name')) { + return $retrieveCategory; + } + } + return ['id' => null]; + } + + /** + * Return category data by category id. + * + * @param int $categoryId + * @return array + */ + private function getResponse($categoryId) + { + $url = $_ENV['app_frontend_url'] . 'rest/all/V1/categories/' . $categoryId; + $this->webApi->write($url, [], WebapiDecorator::GET); + $response = json_decode($this->webApi->read(), true); + $this->webApi->close(); + return $response; + } + + /** + * URL rewrite category present in grid. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php index 12bd4411c3a70..a2e4df3ff82f2 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php @@ -1,6 +1,6 @@ webApi = $webApi; + $urlRewriteIndex->open(); + $categories = $product->getDataFieldConfig('category_ids')['source']->getCategories(); + $rootCategoryArray = []; + foreach ($categories as $index => $category) { + $parentName = $category->getDataFieldConfig('parent_id')['source']->getParentCategory()->getName(); + $rootCategoryArray[$parentName]['name'] = !empty($category->getUrlKey()) + ? strtolower($category->getUrlKey()) + : strtolower($category->getName()); + $rootCategoryArray[$parentName]['index'] = $index; + } + + $stores = $product->getDataFieldConfig('website_ids')['source']->getStores(); + foreach ($stores as $store) { + $rootCategoryName = $store->getDataFieldConfig('group_id')['source'] + ->getStoreGroup() + ->getDataFieldConfig('root_category_id')['source'] + ->getCategory() + ->getName(); + + $this->parentCategoryIndex = $rootCategoryArray[$rootCategoryName]['index']; + + $storeName = $store->getName(); + $filters = [ + [ + 'request_path' => $product->getUrlKey() . '.html', + 'store_id' => $storeName + ], + [ + 'request_path' => $rootCategoryArray[$rootCategoryName]['name'] . '.html', + 'store_id' => $storeName + ], + [ + 'request_path' => + $rootCategoryArray[$rootCategoryName]['name'] . '/' . $product->getUrlKey() . '.html', + 'target_path' => $this->getTargetPath($product, $category), + 'store_id' => $storeName + ], + ]; + foreach ($filters as $filter) { + \PHPUnit_Framework_Assert::assertTrue( + $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), + 'URL Rewrite with request path \'' . $filter['request_path'] . '\' is absent in grid.' + ); + + } + } + } + + /** + * Get target path. + * + * @param FixtureInterface $product + * @param FixtureInterface|null $category + * @return string + */ + private function getTargetPath(FixtureInterface $product, FixtureInterface $category = null) + { + $productId = $product->getId() + ? $product->getId() + : $this->retrieveProductBySku($product->getSku())['id']; + $categoryId = $product->hasData('category_ids') + ? $this->getCategoryId($product) + : ($category ? $category->getId() : ''); + return sprintf($this->targetPathTemplate, $productId, $categoryId); + } + + /** + * Get category id by product. + * + * @param FixtureInterface $product + * @return int + */ + private function getCategoryId(FixtureInterface $product) + { + $productSku = $product->getSku(); + $categoryId = $product->getDataFieldConfig('category_ids')['source'] + ->getCategories()[$this->parentCategoryIndex]->getId(); + $categoryId = $categoryId + ? $categoryId + : $this->retrieveProductBySku($productSku) + ['extension_attributes']['category_links'][$this->parentCategoryIndex]['category_id']; + return $categoryId; + } + + /** + * Retrieve product by sku. + * + * @param string $sku + * @return mixed + */ + public function retrieveProductBySku($sku) + { + $url = $_ENV['app_frontend_url'] . 'rest/all/V1/products/' . $sku; + $this->webApi->write($url, [], WebapiDecorator::GET); + $response = json_decode($this->webApi->read(), true); + $this->webApi->close(); + return $response; + } + + /** + * URL rewrite product present in grid. + * + * @return string + */ + public function toString() + { + return 'URL Rewrite is present in grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductNotInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductNotInGrid.php new file mode 100644 index 0000000000000..66ff1ac205ea3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductNotInGrid.php @@ -0,0 +1,45 @@ +open(); + $requestPath = $product->getUrlKey() . '.html'; + $filter = ['request_path' => $requestPath]; + \PHPUnit_Framework_Assert::assertFalse( + $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter), + 'URL Rewrite with request path \'' . $requestPath . '\' is present in grid.' + ); + } + + /** + * URL rewrite product not present in grid. + * + * @return string + */ + public function toString() + { + return 'URL Rewrite is not present in grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php index 90db4d87c47cb..9b0db0d849b45 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php @@ -1,6 +1,6 @@ urlRewriteIndex = $urlRewriteIndex; + $urlRewriteIndex->open(); + $filter = [ + 'request_path' => $this->getNestingPath($categoryBeforeSave, $nestingLevel), + 'target_path' => $this->getNestingPath($category, $nestingLevel), + 'redirect_type' => $redirectType + ]; + $this->rowVisibleAssertion($filter); + } + + /** + * Assert that category redirect is present in grid. + * + * @param array $filter + * @return void + */ + private function rowVisibleAssertion(array $filter) + { + $filterRow = implode(', ', $filter); + \PHPUnit_Framework_Assert::assertTrue( + $this->urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), + 'Category redirect with request path "' . $filterRow . '" is absent in grid.' + ); + } + + /** + * Return category url path by nesting level. + * + * @param Category $category + * @param int $nestingLevel + * @return string + */ + private function getNestingPath(Category $category, $nestingLevel) + { + if ($nestingLevel === null) { + return strtolower($category->getUrlKey() . '.html'); + } + $filterByRequestPathCondition = []; + for ($nestingIterator = 0; $nestingIterator < $nestingLevel; $nestingIterator++) { + $filterByRequestPathCondition[] = $category->getUrlKey(); + $category = $category->getDataFieldConfig('parent_id')['source']->getParentCategory(); + } + + return strtolower(implode('/', array_reverse($filterByRequestPathCondition)) . '.html'); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Category redirect is present in grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php index 57c1d3d94faf3..6f268c9318e6d 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php @@ -1,6 +1,6 @@ $category) { + $assertUrlRewriteCategoryInGrid->processAssert( + $category, + $webApi, + $urlRewriteIndex, + null, + null, + $key, + $filterByPath, + $redirectType + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Category url rewrites are present in grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewritesRedirectInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewritesRedirectInGrid.php new file mode 100644 index 0000000000000..00b2851996d27 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewritesRedirectInGrid.php @@ -0,0 +1,54 @@ + $category) { + $assertUrlRewriteRedirectInGrid->processAssert( + $category, + $categoriesBeforeSave[$key], + $urlRewriteIndex, + $key, + $redirectType + ); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Category redirects a present in grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml index c219926cace6e..004b5836abd9d 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/StoreId.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/StoreId.php index 8aba563133954..f55bb3675f694 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/StoreId.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/StoreId.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlRewriteIndex.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlRewriteIndex.xml index cdb6b17572d2d..0e7388fedd7d7 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlRewriteIndex.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlRewriteIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Repository/UrlRewrite.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Repository/UrlRewrite.xml index 45ff1d0aa9c98..5498127774d20 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Repository/UrlRewrite.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Repository/UrlRewrite.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php new file mode 100644 index 0000000000000..b9b52cb786afa --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.php @@ -0,0 +1,102 @@ + Categories. + * 3. On the categories editing page change store view to created additional view. + * 4. Change URL key for category "first-test" from default to "first-test-2". Save. + * 5. Change store view to "All store views". + * 6. Move category "first-test" inside "second-test". + * 7. Perform all assertions. + * + * @ZephyrId MAGETWO-45385 + */ +class CategoryUrlRewriteTest extends Injectable +{ + /** + * CatalogCategoryIndex page. + * + * @var CatalogCategoryIndex + */ + private $catalogCategoryIndex; + + /** + * CatalogCategoryEdit page. + * + * @var CatalogCategoryEdit + */ + private $catalogCategoryEdit; + + /** + * Inject page end prepare default category. + * + * @param CatalogCategoryIndex $catalogCategoryIndex + * @param CatalogCategoryEdit $catalogCategoryEdit + * @return array + */ + public function __inject( + CatalogCategoryIndex $catalogCategoryIndex, + CatalogCategoryEdit $catalogCategoryEdit + ) { + $this->catalogCategoryIndex = $catalogCategoryIndex; + $this->catalogCategoryEdit = $catalogCategoryEdit; + } + + /** + * Runs test. + * + * @param Store $storeView + * @param Category $childCategory + * @param Category $parentCategory + * @param Category $categoryUpdates + * @return array + */ + public function test(Store $storeView, Category $childCategory, Category $parentCategory, Category $categoryUpdates) + { + // Preconditions: + $storeView->persist(); + $parentCategory->persist(); + $childCategory->persist(); + + // Steps: + $this->catalogCategoryIndex->open(); + $this->catalogCategoryIndex->getTreeCategories()->selectCategory($childCategory); + $this->catalogCategoryEdit->getFormPageActions()->selectStoreView($storeView->getName()); + $this->catalogCategoryEdit->getEditForm()->fill($categoryUpdates); + $this->catalogCategoryEdit->getFormPageActions()->save(); + $this->catalogCategoryIndex->getTreeCategories()->assignCategory( + $parentCategory->getName(), + $childCategory->getName() + ); + if ($this->catalogCategoryEdit->getModalBlock()->isVisible()) { + $this->catalogCategoryEdit->getModalBlock()->acceptWarning(); + } + + return [ + 'storeView' => $storeView, + 'childCategory' => $childCategory, + 'parentCategory' => $parentCategory + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml new file mode 100644 index 0000000000000..5abbb171eaf81 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CategoryUrlRewriteTest.xml @@ -0,0 +1,21 @@ + + + + + + custom + default + catalogProductSimple::default + default + catalogProductSimple::default + No + UrlKey%isolation% + + + + diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCategoryRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCategoryRewriteEntityTest.php index c3502924b56e0..9bc77f384c4c7 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCategoryRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCategoryRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCustomUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCustomUrlRewriteEntityTest.php index 201a52ce5dec1..41b22ede68473 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCustomUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCustomUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.php index e333fdd2f0618..fafdbc48c9327 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ @@ -47,5 +47,15 @@ + + For Product + product_with_category + Main Website/Main Website Store/Default Store View + cat%isolation%/simp_redirect%isolation%.html + Temporary (302) + description_%isolation% + + + diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.php new file mode 100644 index 0000000000000..ecd176d265ad7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.php @@ -0,0 +1,104 @@ + Catalog. + * 3. Start to create simple product. + * 4. Fill in data according to data set. + * 5. Save Product. + * 6. Perform appropriate assertions. + * + * @ZephyrId MAGETWO-27238 + */ +class CreateProductWithSeveralWebsitesUrlRewriteTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + /* end tags */ + + /** + * Run create product with several websites url rewrite test. + * + * @param CatalogProductSimple $product + * @param CatalogProductIndex $productGrid + * @param CatalogProductNew $newProductPage + * @param FixtureFactory $fixtureFactory + * @param array $websiteCategories + * @return array + */ + public function testCreate( + CatalogProductSimple $product, + CatalogProductIndex $productGrid, + CatalogProductNew $newProductPage, + FixtureFactory $fixtureFactory, + array $websiteCategories + ) { + $categoryParent = []; + $categoryList = []; + $storeList = []; + + // Preconditions + foreach ($websiteCategories as $websiteCategory) { + list($storeGroup, $store, $category) = explode('::', $websiteCategory); + if (!isset($categoryParent[$category])) { + $categoryListItem = $fixtureFactory->createByCode('category', ['dataset' => $category]); + $categoryListItem->persist(); + $categoryParent[$category] = $categoryListItem->getDataFieldConfig('parent_id')['source'] + ->getParentCategory(); + $categoryList[] = $categoryListItem; + } + $storeGroup = $fixtureFactory->createByCode('storeGroup', [ + 'dataset' => $storeGroup, + 'data' => [ + 'root_category_id' => [ + 'category' => $categoryParent[$category] + ] + ] + ]); + $storeGroup->persist(); + $store = $fixtureFactory->createByCode('store', [ + 'dataset' => $store, + 'data' => [ + 'group_id' => [ + 'storeGroup' => $storeGroup + ] + ] + ]); + $store->persist(); + $storeList[] = $store; + } + + $productData = $product->getData(); + $productData['website_ids'] = $storeList; + $productData['category_ids'] = $categoryList; + + $product = $fixtureFactory->createByCode( + 'catalogProductSimple', + [ + 'dataset' => 'default', + 'data' => $productData, + ] + ); + + // Steps + $productGrid->open(); + $productGrid->getGridPageActionBlock()->addProduct('simple'); + $newProductPage->getProductForm()->fill($product); + $newProductPage->getFormPageActions()->save(); + + return ['product' => $product]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml new file mode 100644 index 0000000000000..888cc48969ec4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml @@ -0,0 +1,26 @@ + + + + + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 42 + 50 + 345 + + default::default::default + store_group_new_1::store_new_1::default + store_group_new_2::store_new_2::root_subcategory + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest.php index 0dcc9d8e1985b..739f1b8f6477d 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.php index 4f4526d907be1..d8cd5e05bbabd 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCustomUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php index 9d8491b8afa4b..becd08df5f7d6 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml index f12f8c9117c3d..57e21a846b569 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php index 2c7cf3ecbf4ce..51603afc2c00b 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.php index 04eb7fd5aa8e5..9b576715c35ff 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCustomUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php index 1f9c09fcb5f3c..79c9bfcbef8e8 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/curl/di.xml index 708c9e1c81b21..8bb75fd6f1117 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/LockedUsersGrid.php b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/LockedUsersGrid.php new file mode 100644 index 0000000000000..6316e82baffa2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/LockedUsersGrid.php @@ -0,0 +1,26 @@ + [ + 'selector' => '#lockedAdminsGrid_filter_username', + ], + ]; +} diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/PageActions.php b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/PageActions.php index 326b46c5e6d96..e1f4b1ff9c9d1 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/PageActions.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/PageActions.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/Tab/Role.php b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/Tab/Role.php index 4d2463b1faa4c..87b13f7344e3e 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/Tab/Role.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/Role/Tab/Role.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/UserGrid.php b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/UserGrid.php index 861cbb19c8179..43c9cb5651975 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/UserGrid.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Block/Adminhtml/UserGrid.php @@ -1,6 +1,6 @@ getMessagesBlock()->getErrorMessage(); + $errorMessage = $dashboard->getMessagesBlock()->getErrorMessage(); \PHPUnit_Framework_Assert::assertEquals( self::ERROR_MESSAGE, $errorMessage, diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php index 20f734870f289..20ed56f475e37 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php @@ -1,6 +1,6 @@ getMessagesBlock()->getErrorMessage(); + \PHPUnit_Framework_Assert::assertEquals( + self::FAIL_MESSAGE, + $errorMessage, + 'Password update failed with error: "' . self::FAIL_MESSAGE . '"' + ); + } + + /** + * Returns success message if there is fail message. + * + * @return string + */ + public function toString() + { + return 'Password validation completed successfully.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php index 4fd8e44a90bea..3bfd27205d92e 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Fixture/Role/InRoleUsers.php b/dev/tests/functional/tests/app/Magento/User/Test/Fixture/Role/InRoleUsers.php index 4e1900f0b01f1..c5c354d5203c9 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Fixture/Role/InRoleUsers.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Fixture/Role/InRoleUsers.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Fixture/User/CurrentPassword.php b/dev/tests/functional/tests/app/Magento/User/Test/Fixture/User/CurrentPassword.php index 09a4ba7a91d0b..67d10412b73c1 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Fixture/User/CurrentPassword.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Fixture/User/CurrentPassword.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserIndex.xml b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserIndex.xml index 38b1ff3d1b6cd..73f68e2a96b00 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserIndex.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserLocks.xml b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserLocks.xml new file mode 100644 index 0000000000000..99206a9e059ba --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserLocks.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleEditRole.xml b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleEditRole.xml index 34f6d35190ca4..2835ca096102b 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleEditRole.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleEditRole.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleIndex.xml b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleIndex.xml index 2e326c7eb8111..9372c3c4af416 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleIndex.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/Page/Adminhtml/UserRoleIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/User/Test/Repository/ConfigData.xml index 7b62a73a1af2a..a349ea11af6e3 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -15,5 +15,23 @@ 6 + + + + admin + 1 + Maximum Login Failures to Lockout Account + 2 + + + + + + admin + 1 + Maximum Login Failures to Lockout Account + 6 + + diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Repository/Role.xml b/dev/tests/functional/tests/app/Magento/User/Test/Repository/Role.xml index 6d256383ba8f8..e7af2bd85e00d 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Repository/Role.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/Repository/Role.xml @@ -1,7 +1,7 @@ @@ -47,5 +47,35 @@ Magento_Sales::emails + + + RoleName%isolation% + Custom + %current_password% + + Magento_Backend::dashboard + Magento_AdminNotification::adminnotification + Magento_EncryptionKey::crypt_key + Magento_Backend::content + Magento_Backend::content_elements + Magento_Cms::page + Magento_Cms::save + Magento_Cms::page_delete + + + + + RoleName%isolation% + Custom + %current_password% + + Magento_Backend::dashboard + Magento_Backend::marketing + Magento_Backend::marketing_seo + Magento_Search::search + Magento_UrlRewrite::urlrewrite + Magento_Sitemap::sitemap + + diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml b/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml index 25b812bf77665..d31693a75843f 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml @@ -1,7 +1,7 @@ @@ -41,5 +41,37 @@ %current_password% Active + + + 123123q + + + + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123q + 123123q + + role::role_without_variable + + %current_password% + Active + + + + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123q + 123123q + + role::role_without_synonym + + %current_password% + Active + diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.php index 2003bb4b27770..bac6abefa17cd 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.php @@ -1,6 +1,6 @@ getData(); $data[$isDuplicated] = $adminUser->getData($isDuplicated); $data['role_id'] = ['role' => $user->getDataFieldConfig('role_id')['source']->getRole()]; diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.xml index f2005174d24db..cfbe247b9fe5d 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserEntityTest.xml @@ -1,7 +1,7 @@ @@ -17,7 +17,6 @@ 123123q Active role::Administrators - - %current_password% @@ -33,7 +32,6 @@ 123123q Inactive role::Administrators - - 123123q @@ -72,7 +70,6 @@ 123123q 123123q Active - - %current_password% @@ -87,9 +84,18 @@ 123123q 123123q Active - - %current_password% + + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123q + 123123q + incorrect-password + + diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserRoleEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserRoleEntityTest.php index 42dfaf10b9307..1f44483a23f59 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserRoleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CreateAdminUserRoleEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CustomAclPermissionTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CustomAclPermissionTest.php new file mode 100644 index 0000000000000..c9cf6ccf7cfc6 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/CustomAclPermissionTest.php @@ -0,0 +1,62 @@ +testStepFactory = $testStepFactory; + } + + /** + * Test acl permissions. + * + * @param User $user + * @return array + */ + public function test(User $user) + { + $user->persist(); + $this->testStepFactory->create( + \Magento\User\Test\TestStep\LoginUserOnBackendStep::class, + ['user' => $user] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php index 57de56c7f56f7..4b5914eaab2c2 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php @@ -1,6 +1,6 @@ $user->getUsername(), @@ -118,6 +120,7 @@ public function testDeleteAdminUserEntity( } $this->userIndex->open(); $this->userIndex->getUserGrid()->searchAndOpen($filter); + $this->userEdit->getUserForm()->fill($systemAdmin); $this->userEdit->getPageActions()->delete(); $this->userEdit->getModalBlock()->acceptAlert(); } diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml index 782c3243eaa6b..9d2a2bbcd122d 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml @@ -1,7 +1,7 @@ @@ -9,11 +9,13 @@ 0 + system_admin 1 + system_admin diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteUserRoleEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteUserRoleEntityTest.php index c3f0d766406b2..2a1e55b1db431 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteUserRoleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteUserRoleEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserEntityTest.php index a6074b3f5ac6b..0d72d7d6b2ade 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/LockAdminUserEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml index fed8dd9b34965..56f9fea2e4669 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.php index f570d179cd23e..7e8f8a8eacd71 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UnlockAdminUserTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UnlockAdminUserTest.php new file mode 100644 index 0000000000000..0c8fc0723925b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UnlockAdminUserTest.php @@ -0,0 +1,144 @@ +testStepFactory = $testStepFactory; + $this->adminAuth = $adminAuth; + $this->fixtureFactory = $fixtureFactory; + $this->userLocks = $userLocks; + } + + /** + * Check that login works correctly after unlocking admin user. + * + * @param User $customAdmin + * @param string $incorrectPassword + * @param int $attempts + * @param string $configData + * @return array + */ + public function test( + User $customAdmin, + $incorrectPassword, + $attempts, + $configData + ) { + // Preconditions + $this->configData = $configData; + $this->testStepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $configData] + )->run(); + $customAdmin->persist(); + /** @var User $incorrectUser */ + $incorrectUser = $this->fixtureFactory->createByCode( + 'user', + ['data' => ['username' => $customAdmin->getUsername(), 'password' => $incorrectPassword]] + ); + for ($i = 0; $i < $attempts; $i++) { + $this->adminAuth->open(); + $this->adminAuth->getLoginBlock()->fill($incorrectUser); + $this->adminAuth->getLoginBlock()->submit(); + } + + // Test steps + $this->userLocks->open(); + $this->userLocks->getLockedUsersGrid()->massaction([['username' => $customAdmin->getUsername()]], 'Unlock'); + + return ['user' => $customAdmin]; + } + + /** + * Revert configuration settings. + * + * @return void + */ + public function tearDown() + { + $this->testStepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UnlockAdminUserTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UnlockAdminUserTest.xml new file mode 100644 index 0000000000000..9e0022da502b1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UnlockAdminUserTest.xml @@ -0,0 +1,18 @@ + + + + + + two_attempts_before_lock + custom_admin_with_default_role + honey boo boo + 3 + + + + diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserEntityTest.php index 79c58c434e238..1547d64c60420 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.php index aaf3a42dc1d1d..524136f90031a 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdateAdminUserRoleEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.php new file mode 100644 index 0000000000000..c44ce195c380a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.php @@ -0,0 +1,131 @@ + All Users + * 3. Click on admin record to open > Account Information page. + * 4. Update password providing a new password. + * 5. Save user + * 6. Repeat Steps 4-5 4 times with different passwords. + * 7. Update password providing an original password for the user. + * + * @ZephyrId MAGETWO-48104 + */ +class UpdatePasswordUserEntityPciRequirementsTest extends Injectable +{ + /** + * User edit page on backend. + * + * @var UserEdit + */ + protected $userEdit; + + /** + * Dashboard page on backend. + * + * @var Dashboard + */ + protected $dashboard; + + /** + * Authorization page on backend. + * + * @var AdminAuthLogin + */ + protected $adminAuth; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Setup necessary data for test. + * + * @param UserEdit $userEdit + * @param Dashboard $dashboard + * @param AdminAuthLogin $adminAuth + * @param FixtureFactory $fixtureFactory + * @return void + */ + public function __inject( + UserEdit $userEdit, + Dashboard $dashboard, + AdminAuthLogin $adminAuth, + FixtureFactory $fixtureFactory + ) { + $this->userEdit = $userEdit; + $this->dashboard = $dashboard; + $this->adminAuth = $adminAuth; + $this->fixtureFactory = $fixtureFactory; + } + + /** + * Run Test. + * + * @param User $user + * @param array $passwords + * @return void + */ + public function test( + User $user, + array $passwords + ) { + // Preconditions + $user->persist(); + $initialPassword = $user->getPassword(); + $currentPassword = $user->getPassword(); + $passwords[] = $initialPassword; + + // Steps + $this->adminAuth->open(); + $this->adminAuth->getLoginBlock()->fill($user); + $this->adminAuth->getLoginBlock()->submit(); + + foreach ($passwords as $password) { + $data = [ + 'password' => $password, + 'password_confirmation' => $password, + 'current_password' => $currentPassword, + + ]; + $updatedUser = $this->fixtureFactory->createByCode('user', ['data' => $data]); + + $this->userEdit->open(['user_id' => $user->getUserId()]); + $this->userEdit->getUserForm()->fill($updatedUser); + $this->userEdit->getPageActions()->save(); + $currentPassword = $password; + } + } + + /** + * Logout Admin User from account. + * + * @return void + */ + public function tearDown() + { + if ($this->dashboard->getAdminPanelHeader()->isVisible()) { + $this->dashboard->getAdminPanelHeader()->logOut(); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.xml new file mode 100644 index 0000000000000..7be1764896dc1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UpdatePasswordUserEntityPciRequirementsTest.xml @@ -0,0 +1,19 @@ + + + + + + custom_admin_with_default_role + 123123^q0 + 123123^q1 + 123123^q2 + 123123^q3 + + + + diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UserLoginAfterChangingPermissionsTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UserLoginAfterChangingPermissionsTest.php index 5eb73d2087e01..a0f3f283da2a5 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UserLoginAfterChangingPermissionsTest.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/UserLoginAfterChangingPermissionsTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestStep/CreateUserStep.php b/dev/tests/functional/tests/app/Magento/User/Test/TestStep/CreateUserStep.php new file mode 100644 index 0000000000000..6c3a001ce6b3b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestStep/CreateUserStep.php @@ -0,0 +1,42 @@ +user = $user; + } + + /** + * Run step flow. + * + * @return array + */ + public function run() + { + $this->user->persist(); + + return ['user' => $this->user]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestStep/LoginUserOnBackendStep.php b/dev/tests/functional/tests/app/Magento/User/Test/TestStep/LoginUserOnBackendStep.php index 5e4eb35c80522..9255a906fc857 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/TestStep/LoginUserOnBackendStep.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/TestStep/LoginUserOnBackendStep.php @@ -1,6 +1,6 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml index 85c6a6fd80eec..2b815f5f2b856 100644 --- a/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Usps/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ @@ -54,7 +54,6 @@ 1 - carriers @@ -63,5 +62,21 @@ 0 + + + carriers + 1 + Small Flat-Rate Box + SM FLAT RATE BOX + + + + + carriers + 1 + Variable + VARIABLE + + diff --git a/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml index 6170b8bbe0616..5975885decda8 100644 --- a/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml +++ b/dev/tests/functional/tests/app/Magento/Usps/Test/TestCase/OnePageCheckoutTest.xml @@ -1,7 +1,7 @@ @@ -16,11 +16,11 @@ US_address_1 US_address_1_without_email United States Postal Service - Priority Mail 1-Day - Priority Mail 1-Day + Priority Mail 1-Day Small Flat Rate Box + Priority Mail 1-Day Small Flat Rate Box checkmo - checkmo, usps, shipping_origin_US_CA - test_type:3rd_party_test + checkmo, usps, shipping_origin_US_CA, usps_container_sm_flat_rate_box + test_type:3rd_party_test, severity:S0 @@ -28,18 +28,16 @@ catalogProductSimple::default - configurableProduct::default - bundleProduct::bundle_fixed_product guest default UK_address UK_address United States Postal Service - Priority Mail International - Priority Mail International + Priority Mail Express International Flat Rate Envelope + Priority Mail Express International Flat Rate Envelope checkmo checkmo, usps, shipping_origin_US_CA - test_type:3rd_party_test + test_type:3rd_party_test, severity:S0 diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/Edit/VariableForm.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/Edit/VariableForm.php index 241bdf2d25850..11834b329fa93 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/Edit/VariableForm.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/Edit/VariableForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/FormPageActions.php index 6af36abf59e35..2f38f136446bc 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Block/Adminhtml/System/Variable/FormPageActions.php @@ -1,6 +1,6 @@ persist(); + $cmsPageNew->open(); + + \PHPUnit_Framework_Assert::assertFalse( + $cmsPageNew->getPageForm()->isVariablesBlockVisible(), + 'Access to system variables block is supposed to be restricted.' + ); + } + + /** + * Returns a string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Access to system variables block is restricted and block is not visible.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php index bf8e72e657a5f..59337ca7e713b 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Handler/SystemVariable/Curl.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Handler/SystemVariable/Curl.php index 30088ca1315ec..694d0d6029a97 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Handler/SystemVariable/Curl.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Handler/SystemVariable/Curl.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Page/Adminhtml/SystemVariableNew.xml b/dev/tests/functional/tests/app/Magento/Variable/Test/Page/Adminhtml/SystemVariableNew.xml index cf34003c77085..5f9c2d48160ff 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Page/Adminhtml/SystemVariableNew.xml +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Page/Adminhtml/SystemVariableNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Repository/SystemVariable.xml b/dev/tests/functional/tests/app/Magento/Variable/Test/Repository/SystemVariable.xml index 8e7183210d726..9bb02967b2ca3 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Repository/SystemVariable.xml +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Repository/SystemVariable.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/CreateCustomVariableEntityTest.php b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/CreateCustomVariableEntityTest.php index ccb146635719f..8e1d50ae5f8bc 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/CreateCustomVariableEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/CreateCustomVariableEntityTest.php @@ -1,6 +1,6 @@ @@ -19,6 +19,7 @@ + stable:no variableCode%isolation% variableName%isolation% <p>variableName%isolation%</p> diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/CustomAclPermissionTest.xml b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/CustomAclPermissionTest.xml new file mode 100644 index 0000000000000..a1dad33871bdc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/CustomAclPermissionTest.xml @@ -0,0 +1,16 @@ + + + + + + custom_admin_with_role_without_variable + default + + + + diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/DeleteCustomVariableEntityTest.php b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/DeleteCustomVariableEntityTest.php index 6b3e819eaf903..d613c9c0ae41c 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/DeleteCustomVariableEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/DeleteCustomVariableEntityTest.php @@ -1,6 +1,6 @@ + to_maintain:yes diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml index 0bfe945d63a78..ca580d51ae382 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/UpdateCustomVariableEntityTest.php b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/UpdateCustomVariableEntityTest.php index 6e9631c7a95f9..48c23ff465fd4 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/UpdateCustomVariableEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/UpdateCustomVariableEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Variable/Test/etc/curl/di.xml index ff3e3796cb403..cf32b3a56cd8c 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/etc/curl/di.xml +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/etc/curl/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Block/Onepage/Payment/Method/Vault.php b/dev/tests/functional/tests/app/Magento/Vault/Test/Block/Onepage/Payment/Method/Vault.php new file mode 100644 index 0000000000000..dc0d7c87a37f5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Block/Onepage/Payment/Method/Vault.php @@ -0,0 +1,67 @@ +vaultCheckbox, $paymentMethod); + $this->_rootElement->find($saveCard, Locator::SELECTOR_CSS, 'checkbox')->setValue($creditCardSave); + } + + /** + * Check if Save credit card check box is visible. + * + * @param string $paymentMethod + * @return bool + */ + public function isVaultVisible($paymentMethod) + { + $saveCard = sprintf($this->vaultCheckbox, $paymentMethod); + return $this->_rootElement->find($saveCard, Locator::SELECTOR_CSS, 'checkbox')->isVisible(); + } + + /** + * Verify if saved credit card is present as a payment option. + * + * @param string $creditCard + * @return bool + */ + public function isSavedCreditCardPresent($creditCard) + { + $paymentLabelSelector = sprintf($this->creditCardSelector, $creditCard); + return $this->_rootElement->find($paymentLabelSelector, Locator::SELECTOR_XPATH)->isVisible(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Block/StoredPayments.php b/dev/tests/functional/tests/app/Magento/Vault/Test/Block/StoredPayments.php index 3aad566537fbb..e9716c505eb76 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/Block/StoredPayments.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Block/StoredPayments.php @@ -1,6 +1,6 @@ creditCardSelector, $creditCard); - return $this->browser->find($paymentLabelSelector, Locator::SELECTOR_XPATH)->isVisible(); - } -} diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php index fbad27ed64992..53231c042c2d6 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php @@ -1,6 +1,6 @@ getVaultPaymentBlock()->isVaultVisible($payment), + 'Save for later use checkbox is present.' + ); + } + + /** + * Returns string representation of successful assertion. + * + * @return string + */ + public function toString() + { + return 'Save for later use checkbox is not present in credit card form.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php index 7679c870b726c..74bf6fa2e903e 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php @@ -1,6 +1,6 @@ - + diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Page/StoredPaymentMethods.xml b/dev/tests/functional/tests/app/Magento/Vault/Test/Page/StoredPaymentMethods.xml index 2baf7d7d57fd7..202d8d6991e05 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/Page/StoredPaymentMethods.xml +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Page/StoredPaymentMethods.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/CreateVaultOrderBackendTest.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/CreateVaultOrderBackendTest.php index 3c306280215ea..38aa3c1c8744d 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/CreateVaultOrderBackendTest.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/CreateVaultOrderBackendTest.php @@ -1,6 +1,6 @@ fillShippingMethod($shipping); if ($key >= 2) { // if this order will be placed via stored credit card - $this->useSavedCreditCard($payment); + $this->useSavedCreditCard($payment['vault']); } else { - $this->selectPaymentMethod($payment, $payment['creditCardClass'], $payment['creditCard']); + $this->selectPaymentMethod($payment, $payment['creditCard']); $this->saveCreditCard($payment, $creditCardSave); } $this->placeOrder(); @@ -104,8 +106,7 @@ public function test( for ($i = 2; $i < $paymentsCount; $i++) { $deletedCard = $this->deleteCreditCardFromMyAccount( $customer, - $payments[$i]['creditCard'], - $payments[$i]['creditCardClass'] + $payments[$i]['creditCard'] ); $this->addToCart($products); $this->proceedToCheckout(); @@ -118,9 +119,12 @@ public function test( } /** + * Setup configuration step. + * * @param $configData + * @return void */ - protected function setupConfiguration($configData) + private function setupConfiguration($configData) { $setupConfigurationStep = ObjectManager::getInstance()->create( \Magento\Config\Test\TestStep\SetupConfigurationStep::class, @@ -131,7 +135,7 @@ protected function setupConfiguration($configData) } /** - * Create products + * Create products step. * * @param string $productList * @return array @@ -148,6 +152,8 @@ protected function prepareProducts($productList) } /** + * Add to cart step. + * * @param array $products * @return void */ @@ -161,6 +167,8 @@ protected function addToCart(array $products) } /** + * Proceed to checkout step. + * * @return void */ protected function proceedToCheckout() @@ -172,7 +180,10 @@ protected function proceedToCheckout() } /** + * Create customer step. + * * @param array $customer + * @return Customer */ protected function createCustomer(array $customer) { @@ -185,8 +196,11 @@ protected function createCustomer(array $customer) } /** + * Select Checkout method step. + * * @param $checkoutMethod * @param $customer + * @return void */ protected function selectCheckoutMethod($checkoutMethod, $customer) { @@ -201,7 +215,10 @@ protected function selectCheckoutMethod($checkoutMethod, $customer) } /** + * Fill shipping address step. + * * @param array $shippingAddress + * @return void */ protected function fillShippingAddress(array $shippingAddress) { @@ -213,9 +230,10 @@ protected function fillShippingAddress(array $shippingAddress) } /** - * Add products to cart + * Add products to cart. * * @param array $shipping + * @return void */ protected function fillShippingMethod(array $shipping) { @@ -227,17 +245,18 @@ protected function fillShippingMethod(array $shipping) } /** + * Select payment method step. + * * @param array $payment - * @param $creditCardClass * @param array $creditCard + * @return void */ - protected function selectPaymentMethod(array $payment, $creditCardClass, array $creditCard) + protected function selectPaymentMethod(array $payment, array $creditCard) { $selectPaymentMethodStep = ObjectManager::getInstance()->create( \Magento\Checkout\Test\TestStep\SelectPaymentMethodStep::class, [ 'payment' => $payment, - 'creditCardClass' => $creditCardClass, 'creditCard' => $creditCard, ] ); @@ -249,6 +268,7 @@ protected function selectPaymentMethod(array $payment, $creditCardClass, array $ * * @param $payment * @param $creditCardSave + * @return void */ protected function saveCreditCard($payment, $creditCardSave) { @@ -263,6 +283,8 @@ protected function saveCreditCard($payment, $creditCardSave) } /** + * Fill billing information step. + * * @return void */ protected function fillBillingInformation() @@ -274,6 +296,8 @@ protected function fillBillingInformation() } /** + * Place order step. + * * @return void */ protected function placeOrder() @@ -285,30 +309,34 @@ protected function placeOrder() } /** + * Use saved credit card step. + * * @param $payment + * @return void */ protected function useSavedCreditCard($payment) { $useSavedCreditCardStep = ObjectManager::getInstance()->create( \Magento\Vault\Test\TestStep\UseSavedPaymentMethodStep::class, - ['payment' => $payment] + ['vault' => $payment] ); $useSavedCreditCardStep->run(); } /** + * Delete credit card from My Account step. + * * @param $customer * @param $creditCard - * @param $creditCardClass + * @return array */ - protected function deleteCreditCardFromMyAccount($customer, $creditCard, $creditCardClass) + protected function deleteCreditCardFromMyAccount($customer, $creditCard) { $deleteCreditCardFromMyAccountStep = ObjectManager::getInstance()->create( \Magento\Vault\Test\TestStep\DeleteCreditCardFromMyAccountStep::class, [ 'customer' => $customer, - 'creditCard' => $creditCard, - 'creditCardClass' => $creditCardClass + 'creditCard' => $creditCard ] ); $deletedCard = $deleteCreditCardFromMyAccountStep->run(); diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml index 5a2e2903e2c49..c4034ba4f7c23 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/DeleteSavedCreditCardTest.xml @@ -1,7 +1,7 @@ @@ -17,36 +17,50 @@ braintree - credit_card_braintree - visa_braintree + visa_default + + braintree + payflowpro - credit_card - amex_default + visa_alt + + payment + braintree - credit_card_braintree - visa_braintree + visa_default + + braintree + + + + braintree_cc_vault payflowpro - credit_card - amex_default + visa_alt + + payment + + + + payflowpro_cc_vault Yes braintree, payflowpro, braintree_use_vault, payflowpro_use_vault - test_type:3rd_party_test + test_type:3rd_party_test, severity:S1 diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/ReorderUsingVaultTest.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/ReorderUsingVaultTest.php index c3b82af6949c4..59ea6f199eb8e 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/ReorderUsingVaultTest.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestCase/ReorderUsingVaultTest.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; + $this->assertSaveCreditCardOptionNotPresent = $assertSaveCreditCardOptionNotPresent; + $this->payment = $payment; + $this->isVaultPresent = $isVaultPresent; + } + + /** + * Run step that verifies if 'Save for later use' checkbox is not present in credit card form. + * + * @return void + */ + public function run() + { + if ($this->isVaultPresent === false) { + $this->assertSaveCreditCardOptionNotPresent->processAssert( + $this->checkoutOnepage, + $this->payment['method'] + ); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php index c3cb46347dd8c..0c798b5bbbdd2 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteCreditCardFromMyAccountStep.php @@ -1,92 +1,93 @@ storedPaymentMethodsPage = $storedPaymentMethodsPage; $this->customer = $customer; $this->objectManager = $objectManager; $this->customerAccountIndex = $customerAccountIndex; - $this->fixtureFactory = $fixtureFactory; $this->assertStoredPaymentDeletedMessage = $assertStoredPaymentDeletedMessage; - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); + $this->creditCard = $creditCard; } /** - * @inheritdoc + * Run Delete credit card from My Account step. * * @return array */ diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteStoredPaymentStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteStoredPaymentStep.php index b2b857f9e36d8..cc218f96db84a 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteStoredPaymentStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/DeleteStoredPaymentStep.php @@ -1,6 +1,6 @@ orderCreatePage = $orderCreateIndex; $this->payment = $payment; - $this->creditCard = $fixtureFactory->createByCode($creditCardClass, ['dataset' => $creditCard['dataset']]); + $this->creditCard = $creditCard; $this->creditCardSave = $creditCardSave; } diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardStep.php index 0f06f5f636bdc..3aa1d527995e8 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/SaveCreditCardStep.php @@ -1,6 +1,6 @@ checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock()->saveCreditCard( + $this->checkoutOnepage->getVaultPaymentBlock()->saveCreditCard( $this->payment['method'], $this->creditCardSave ); diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseSavedPaymentMethodStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseSavedPaymentMethodStep.php index b4b21670d2e0c..f28370f3c18c0 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseSavedPaymentMethodStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseSavedPaymentMethodStep.php @@ -1,6 +1,6 @@ checkoutOnepage = $checkoutOnepage; - $this->payment = $payment; + $this->vault = $vault; } /** @@ -46,7 +46,6 @@ public function __construct (CheckoutOnepage $checkoutOnepage, array $payment) */ public function run() { - $this->payment['method'] .= '_item_'; - $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->payment); + $this->checkoutOnepage->getPaymentBlock()->selectPaymentMethod($this->vault); } } diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php index ad693923955d4..279a516415349 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/TestStep/UseVaultPaymentTokenStep.php @@ -1,6 +1,6 @@ orderCreatePage = $orderCreateIndex; - $this->payment = $payment; + $this->vault = $vault; } /** @@ -39,8 +39,7 @@ public function __construct(OrderCreateIndex $orderCreateIndex, array $payment) public function run() { $block = $this->orderCreatePage->getCreateBlock(); - $this->payment['method'] .= '_cc_vault'; - $block->selectPaymentMethod($this->payment); - $block->selectVaultToken('token_switcher_' . $this->payment['method']); + $block->selectPaymentMethod($this->vault); + $block->selectVaultToken('token_switcher_' . $this->vault['method']); } } diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Vault/Test/etc/di.xml new file mode 100644 index 0000000000000..5c79b5a50de66 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/etc/di.xml @@ -0,0 +1,19 @@ + + + + + + S2 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml index 6b4f31a329d67..cea4bd9ba1bf5 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/etc/testcase.xml @@ -1,7 +1,7 @@ @@ -37,7 +37,8 @@ - + + @@ -55,7 +56,8 @@ - + + @@ -63,4 +65,7 @@ + + + diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/Fpt.php b/dev/tests/functional/tests/app/Magento/Weee/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/Fpt.php index b4d8e9898e14c..b1a03190c9d5a 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/Fpt.php +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/Block/Adminhtml/Product/Edit/Section/ProductDetails/Fpt.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/Page/CheckoutCart.xml b/dev/tests/functional/tests/app/Magento/Weee/Test/Page/CheckoutCart.xml index 801840de25e4a..ca8ce8871dbf5 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/Page/CheckoutCart.xml +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/Page/CheckoutCart.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/Page/Product/CatalogProductView.xml b/dev/tests/functional/tests/app/Magento/Weee/Test/Page/Product/CatalogProductView.xml index 9f46c732939bd..bf99683680f19 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/Page/Product/CatalogProductView.xml +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/Page/Product/CatalogProductView.xml @@ -1,7 +1,7 @@ @@ -9,4 +9,4 @@ - \ No newline at end of file + diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Weee/Test/Repository/ConfigData.xml index d1953ff74e3b8..6151278d7a753 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/Repository/ConfigData.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.php b/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.php index e430afbbad197..dfc6028903f6d 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.php +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.php @@ -1,6 +1,6 @@ + to_maintain:yes Check not taxed FPT display set to Excluding, Description and Including FPT on product with custom option catalog price Excluding Tax shipping_tax_class_taxable_goods,tax_with_fpt_cat_excl_disc_on_excl with_custom_option_and_fpt @@ -28,6 +29,7 @@ + to_maintain:yes Check not taxed FPT display set to Including FPT and Description on product with custom option catalog price Excluding Tax shipping_tax_class_taxable_goods,tax_with_fpt_cat_excl_disc_on_incl, display_including_tax with_custom_option_and_fpt @@ -50,6 +52,7 @@ + stable:no Check not taxed FPT display set to Excluding, Description and Including FPT on product with special price catalog price Excluding Tax shipping_tax_class_taxable_goods,tax_with_fpt_cat_excl_disc_on_incl, display_including_tax with_special_price_and_fpt @@ -72,6 +75,7 @@ + stable:no Check not taxed FPT display set to Including FPT and Description on product with special price catalog price Excluding Tax shipping_tax_class_taxable_goods,tax_with_fpt_cat_excl_disc_on_excl with_special_price_and_fpt @@ -92,6 +96,7 @@ + to_maintain:yes Check taxed FPT display set to Excluding, Description and Including FPT on product with with custom option catalog price Excluding Tax shipping_tax_class_taxable_goods,tax_with_fpt_taxed_cat_excl_disc_on_excl with_custom_option_and_fpt @@ -204,6 +209,7 @@ + MAGETWO-44968: FPT Final price includes tax on custom option, when display is set to excluding tax Check taxed FPT display set to Excluding, Description and Including FPT on product with with custom option and catalog price Including Tax shipping_tax_class_taxable_goods,tax_with_fpt_taxed_cat_incl_disc_on_excl with_custom_option_and_fpt diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Weee/Test/etc/di.xml index 30be698de32ea..d93e2899c8536 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/ChosenOption.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/ChosenOption.php index 08acc10b83946..d189c8274bf5f 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/ChosenOption.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/ChosenOption.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogCategoryLink/Form.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogCategoryLink/Form.php index cb13c97df7120..97cf4db4add37 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogCategoryLink/Form.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogCategoryLink/Form.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.php index f86ce2c4cddd9..046a245c6f9aa 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink.php index 11a25fffcfba3..b7276a92a4c99 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink/Grid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink/Grid.php index 35c28d9430901..64599147d6b02 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogProductLink/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsPageLink/Grid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsPageLink/Grid.php index 860a1d71d209e..4ba9edf208c04 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsPageLink/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsPageLink/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsStaticBlock/Grid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsStaticBlock/Grid.php index bf7a058f01247..793164127509e 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsStaticBlock/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CmsStaticBlock/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/RecentlyViewedProducts.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/RecentlyViewedProducts.php index 37c23f64b123a..bc31b50f55f14 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/RecentlyViewedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/RecentlyViewedProducts.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Settings.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Settings.php index d6fade224c285..38e880fa4a8fd 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Settings.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Settings.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/GenericPages.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/GenericPages.php index 0f3d738694b09..3cc6eb6b04dc7 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/GenericPages.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/GenericPages.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/Product/Grid.php index f46b4916862ae..1455b9f2de6ca 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/Product/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/Product/Grid.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/WidgetInstanceForm.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/WidgetInstanceForm.php index 87fddd2bca997..2fdd4c79ed97f 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/WidgetInstanceForm.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/WidgetInstanceType/WidgetInstanceForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php index 50a5657a47830..9d50393ed5c15 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/WidgetGrid.php @@ -1,18 +1,26 @@ [ 'selector' => 'input[name="title"]', ], + 'theme_id' => [ + 'selector' => 'select[name="theme_id"]', + 'input' => 'select', + ], ]; + + /** + * Returns values of theme_id filter. + * + * @return array + */ + public function getThemeIdValues() + { + $values = []; + $themeFilter = $this->filters['theme_id']; + $strategy = empty($themeFilter['strategy']) ? Locator::SELECTOR_CSS : $themeFilter['strategy']; + $element = $this->_rootElement->find($themeFilter['selector'], $strategy, $themeFilter['input']); + $options = $element->getElements($this->notEmptyOptionsSelector); + foreach ($options as $option) { + $values[] = $option->getText(); + } + + return $values; + } } diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/WidgetForm.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/WidgetForm.php index efdcf1063349e..098853754d807 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/WidgetForm.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/WidgetForm.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php index e1a8bfcc990e5..0b1a194768b24 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php @@ -1,6 +1,6 @@ getThemeId(); + } + $widgetInstanceIndex->open(); + $actualValues = $widgetInstanceIndex->getWidgetGrid()->getThemeIdValues(); + \PHPUnit_Framework_Assert::assertEmpty( + array_diff($expectedValues, $actualValues), + 'Widget grid theme filter doesn\'t contain all possible values from created widgets.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Widget grid theme filter contains all possible values from created widgets.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php index f45b6184eec24..f0a29b4b3d42d 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php @@ -1,6 +1,6 @@ $widget->getTitle()]; + $filter = ['title' => $widget->getTitle(), 'theme_id' => $widget->getThemeId()]; $widgetInstanceIndex->open(); \PHPUnit_Framework_Assert::assertTrue( $widgetInstanceIndex->getWidgetGrid()->isRowVisible($filter), @@ -37,7 +40,7 @@ public function processAssert(Widget $widget, WidgetInstanceIndex $widgetInstanc } /** - * Returns a string representation of the object + * Returns a string representation of the object. * * @return string */ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php index 4825fd4958ff8..adc505d291606 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php @@ -1,6 +1,6 @@ cmsIndex->open(); + $this->cmsIndex->getCompareLinkBlock()->waitForCompareProductsLinks(); $this->cmsIndex->getLinksBlock()->openLink("Compare Products"); $this->catalogProductCompare->getCompareProductsBlock()->removeAllProducts(); } diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php index f2d4a3146fc3a..1fd3e62000c50 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php @@ -1,6 +1,6 @@ processAssert($widget, $widgetInstanceIndex); + } + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Widgets are present in widget grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget.xml index 282c3256781b9..526a247be3c71 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget/Parameters.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget/Parameters.php index 3504cd0ecdf1c..3ee2cd240a6f4 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget/Parameters.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Fixture/Widget/Parameters.php @@ -1,6 +1,6 @@ [ 'CMS Page Link' => 'cms_page_link', + 'Recently Viewed Products' => 'recently_viewed', ], 'block' => [ 'Main Content Area' => 'content', diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/WidgetInterface.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/WidgetInterface.php index 09e32bddf0527..a66f5561b0710 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/WidgetInterface.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Handler/Widget/WidgetInterface.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceIndex.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceIndex.xml index 574bcea36c975..61f71f946fefd 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceIndex.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceNew.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceNew.xml index 18db48244fa37..25866d73c008f 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceNew.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Page/Adminhtml/WidgetInstanceNew.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml index dc39ed7fa1259..34194434be2bd 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget.xml @@ -1,7 +1,7 @@ @@ -25,5 +25,20 @@ cmsPageLink + + + Recently Viewed Products + Title_%isolation% + Magento Blank + + all_store_views + + + for_viewed_products + + + recentlyViewedProducts + + diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml index 6b1651de83234..55a6d17a56ecc 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml index b463ef34f6855..f2a059b11ea3e 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php index 235361aee8b7e..3f8d7e8d80fc4 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php @@ -1,6 +1,6 @@ caches = $caches; $this->adjustCacheSettings(); - + // Steps $this->widgetInstanceIndex->open(); $this->widgetInstanceIndex->getPageActionsBlock()->addNew(); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml index 42d81d2f16c81..47721259de3bb 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml @@ -1,13 +1,14 @@ + severity:S1 CMS Static Block Magento Luma Title_%isolation% @@ -15,11 +16,10 @@ on_category cmsStaticBlock - - test_type:extended_acceptance_test + test_type:extended_acceptance_test, severity:S1, stable:no CMS Page Link Magento Luma Title_%isolation% @@ -31,6 +31,7 @@ + severity:S1 Recently Viewed Products Magento Luma Title_%isolation% @@ -38,10 +39,10 @@ for_viewed_products recentlyViewedProducts - + severity:S1 Recently Compared Products Magento Luma Title_%isolation% @@ -49,10 +50,10 @@ for_compared_products recentlyComparedProducts - + severity:S1, stable:no Catalog Category Link Magento Luma Title_%isolation% @@ -60,11 +61,10 @@ for_category_link catalogCategoryLink - - test_type:extended_acceptance_test + test_type:extended_acceptance_test, severity:S1 Catalog Product Link Magento Luma Title_%isolation% @@ -72,11 +72,12 @@ on_product_link catalogProductLink - + MAGETWO-58146: There is no cache invalidate popup after creating widget with disabled block_html cache type + severity:S2 Disabled CMS Static Block Magento Luma @@ -91,6 +92,8 @@ + MAGETWO-58146: There is no cache invalidate popup after creating widget with disabled block_html cache type + severity:S3 Invalidated Catalog Category Link Magento Luma @@ -105,6 +108,7 @@ + severity:S1, stable:no Catalog New Products List Magento Luma Title_%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.php new file mode 100644 index 0000000000000..d642e8cdf3d43 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.php @@ -0,0 +1,57 @@ +createByCode('widget', ['dataset' => $widget]); + $widget->persist(); + $widgetInstances[] = $widget; + } + + return ['widgets' => $widgetInstances]; + } + + /** + * Delete all widgets. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create(\Magento\Widget\Test\TestStep\DeleteAllWidgetsStep::class)->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.xml new file mode 100644 index 0000000000000..d863a164926eb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetsEntityTest.xml @@ -0,0 +1,18 @@ + + + + + + severity:S3 + default + recently_viewed_products_on_blank_theme + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/DeleteWidgetEntityTest.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/DeleteWidgetEntityTest.php index ba89d591e3640..cb25e550bb637 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/DeleteWidgetEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/DeleteWidgetEntityTest.php @@ -1,6 +1,6 @@ + severity:S1 default diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml index 99c383d8748ee..88c53e848eb10 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml @@ -1,13 +1,14 @@ + severity:S2 Content > Widgets Widgets diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestStep/DeleteAllWidgetsStep.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestStep/DeleteAllWidgetsStep.php index 24fb829362d87..e271027c51ec4 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestStep/DeleteAllWidgetsStep.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestStep/DeleteAllWidgetsStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/etc/di.xml new file mode 100644 index 0000000000000..ad635370efa1e --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/etc/di.xml @@ -0,0 +1,79 @@ + + + + + + S2 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S2 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S3 + + + + + S3 + + + diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Adminhtml/Customer/Edit/Tab/Wishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Adminhtml/Customer/Edit/Tab/Wishlist.php index 60f8bfa3c3eef..2e0ca5eb6a579 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Adminhtml/Customer/Edit/Tab/Wishlist.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Adminhtml/Customer/Edit/Tab/Wishlist.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Sharing.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Sharing.php index 934295e7cb89a..6604a496e3deb 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Sharing.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Sharing.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php index 47f787da38b04..328f815bd4465 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist.php @@ -1,6 +1,6 @@ waitFormToLoad(); + $this->_rootElement->hover(); $this->_rootElement->find($this->updateButton)->click(); } diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items.php index 37b687a212765..4b9921c14cd3c 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items.php @@ -1,6 +1,6 @@ _rootElement->find($this->viewDetails); if ($viewDetails->isVisible()) { $this->_rootElement->find($this->footer, Locator::SELECTOR_XPATH)->click(); - $viewDetails->click(); + $viewDetails->hover(); $labels = $this->_rootElement->getElements($this->optionLabel); $values = $this->_rootElement->getElements($this->optionValue); $data = []; foreach ($labels as $key => $label) { - if (!$label->isVisible()) { - $viewDetails->click(); - } + $viewDetails->hover(); $data[] = [ 'title' => $label->getText(), 'value' => str_replace('$', '', $values[$key]->getText()), @@ -161,7 +166,19 @@ public function clickEdit() */ public function hoverProductBlock() { - $this->_rootElement->find($this->price)->hover(); + $this->_rootElement->find($this->priceInGrid)->hover(); + } + + /** + * Returns product price + * + * @param string $currency + * @return string + */ + public function getPrice($currency = '$') + { + $price = $this->_rootElement->find($this->price)->getText(); + return str_replace($currency, '', $price); } /** diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.xml b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.xml index 2ac8de2947b54..818896721580a 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.xml +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Block/Customer/Wishlist/Items/Product.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php index b5fe6e2af4ea5..280707dcef3ec 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php @@ -1,6 +1,6 @@ getLinksBlock()->openLink('My Account'); + $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Wish List'); + $wishlistItem = $wishlistIndex->getWishlistBlock()->getProductItemsBlock()->getItemProduct($product); + + \PHPUnit_Framework_Assert::assertNotEquals( + '0.00', + $wishlistItem->getPrice(), + $product->getName() . ' has zero price on Wish List page.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product price is not zero in default Wish List.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php index 32baaa6bd0561..5fe666061ead9 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Page/WishlistShare.xml b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Page/WishlistShare.xml index 67d2f24d22551..9ce7629799d52 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Page/WishlistShare.xml +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Page/WishlistShare.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AbstractWishlistTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AbstractWishlistTest.php index 6c76e927fa56e..9e798f45d62e7 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AbstractWishlistTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AbstractWishlistTest.php @@ -1,6 +1,6 @@ createProducts($product)[0]; // Steps: $this->loginCustomer($customer); - $this->addToWishlist([$product], true); + $this->addToWishlist([$product], $configure); return ['product' => $product]; } diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml index 0557fa298ce98..9d71f0203b082 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductToWishlistEntityTest.xml @@ -1,13 +1,14 @@ + stable:no catalogProductSimple::default @@ -38,16 +39,25 @@ + to_maintain:yes bundleProduct::bundle_dynamic_product + to_maintain:yes bundleProduct::bundle_fixed_product + + configurableProduct::default + false + + + + diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductsToCartFromCustomerWishlistOnFrontendTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductsToCartFromCustomerWishlistOnFrontendTest.php index cf16a045c3487..caaf179cec4ac 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductsToCartFromCustomerWishlistOnFrontendTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/AddProductsToCartFromCustomerWishlistOnFrontendTest.php @@ -1,6 +1,6 @@ + stable:no catalogProductSimple::product_100_dollar 2 @@ -20,6 +21,7 @@ + stable:no catalogProductSimple::default catalogProductVirtual::product_50_dollar catalogProductSimple::default @@ -41,18 +43,21 @@ + stable:no configurableProduct::default 3 + to_maintain:yes bundleProduct::bundle_dynamic_product 2 + to_maintain:yes bundleProduct::bundle_fixed_product 2 diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnBackendTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnBackendTest.php index 21841a70b356d..73c2ab258f177 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnBackendTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnBackendTest.php @@ -1,6 +1,6 @@ + to_maintain:yes catalogProductSimple::with_two_custom_option diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnFrontendTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnFrontendTest.php index 3738dd0631e82..91e8d2daa76e9 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnFrontendTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ConfigureProductInCustomerWishlistOnFrontendTest.php @@ -1,6 +1,6 @@ + to_maintain:yes catalogProductSimple::with_two_custom_option + stable:no configurableProduct::default + to_maintain:yes bundleProduct::bundle_dynamic_product + stable:no downloadableProduct::with_two_separately_links + stable:no groupedProduct::three_simple_products diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductFromCustomerWishlistOnBackendTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductFromCustomerWishlistOnBackendTest.php index aca814aebca6a..522c46eb5ab0b 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductFromCustomerWishlistOnBackendTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductFromCustomerWishlistOnBackendTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductsFromWishlistOnFrontendTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductsFromWishlistOnFrontendTest.php index 361e80ea56b02..172a1cfcea52f 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductsFromWishlistOnFrontendTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/DeleteProductsFromWishlistOnFrontendTest.php @@ -1,6 +1,6 @@ + stable:no catalogProductSimple::product_100_dollar catalogProductVirtual::product_50_dollar @@ -16,6 +17,7 @@ + stable:no catalogProductVirtual::product_50_dollar 1 @@ -23,6 +25,7 @@ + stable:no catalogProductSimple::default catalogProductVirtual::product_50_dollar catalogProductSimple::default @@ -57,6 +60,7 @@ + stable:no downloadableProduct::with_two_separately_links 1 @@ -64,6 +68,7 @@ + stable:no groupedProduct::three_simple_products 1 diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/MoveProductFromShoppingCartToWishlistTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/MoveProductFromShoppingCartToWishlistTest.php index 7ff599cf43df0..be799e75b7fa7 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/MoveProductFromShoppingCartToWishlistTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/MoveProductFromShoppingCartToWishlistTest.php @@ -1,6 +1,6 @@ + stable:no catalogProductSimple::default @@ -20,6 +21,7 @@ + to_maintain:yes downloadableProduct::with_two_separately_links @@ -35,6 +37,7 @@ + stable:no bundleProduct::bundle_dynamic_product @@ -42,6 +45,7 @@ + stable:no bundleProduct::bundle_fixed_product diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ShareWishlistEntityTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ShareWishlistEntityTest.php index 866b60f3dc26a..727a1fe1a291c 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ShareWishlistEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ShareWishlistEntityTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ViewProductInCustomerWishlistOnBackendTest.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ViewProductInCustomerWishlistOnBackendTest.php index 06b0bfa77bf1d..f9871d522ed67 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ViewProductInCustomerWishlistOnBackendTest.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestCase/ViewProductInCustomerWishlistOnBackendTest.php @@ -1,6 +1,6 @@ + to_maintain:yes catalogProductSimple::with_two_custom_option diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestStep/AddProductsToWishlistStep.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestStep/AddProductsToWishlistStep.php index f877181a9f8eb..01d1983b74518 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestStep/AddProductsToWishlistStep.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/TestStep/AddProductsToWishlistStep.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance.xml index 61438075dd276..e7572c09769fc 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance_unstable.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance_unstable.xml index ac37fc159b40d..bdcabedb67413 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance_unstable.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/acceptance_unstable.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/basic.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/basic.xml index 4b4ab839d3463..a4c3de08d5d66 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/basic.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/basic.xml @@ -1,17 +1,12 @@ - - - - - diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/basic_green.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/basic_green.xml new file mode 100644 index 0000000000000..6dfbc16f4bec4 --- /dev/null +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/basic_green.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/category.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/category.xml index 0a98e3795479e..6446f85b437b4 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/category.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/category.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/extended_acceptance.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/extended_acceptance.xml index 899288ac303d7..4b54dba7957d5 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/extended_acceptance.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/extended_acceptance.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/installation.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/installation.xml index c6aeb810a8e5f..136c538275069 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/installation.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/installation.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/mvp.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/mvp.xml index 34241bf28e0fe..edfc83710b2fc 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/mvp.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/mvp.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml index 6a5c6e5d904dd..a246a677d3853 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/setup.xml @@ -1,7 +1,7 @@ @@ -11,5 +11,8 @@ + + + diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/upgrade.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/upgrade.xml new file mode 100644 index 0000000000000..c1debc9ea82da --- /dev/null +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/upgrade.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/dev/tests/functional/utils/bootstrap.php b/dev/tests/functional/utils/bootstrap.php index ca3e7a0b3e392..01ee1d1a71937 100644 --- a/dev/tests/functional/utils/bootstrap.php +++ b/dev/tests/functional/utils/bootstrap.php @@ -1,6 +1,6 @@ file_get_contents($filePath), + 'name' => $fileName, + 'date' => filectime($filePath), + ]; + } +} + +echo serialize($files); diff --git a/dev/tests/functional/utils/generate.php b/dev/tests/functional/utils/generate.php index 78cf8cad0693b..eb7ef5a159824 100644 --- a/dev/tests/functional/utils/generate.php +++ b/dev/tests/functional/utils/generate.php @@ -1,17 +1,19 @@ create($_SERVER); - -// Generate repositories -$magentoObjectManager->get(\Magento\Framework\App\State::class)->setAreaCode('frontend'); - +// Remove previously generated static classes +$fs = $magentoObjectManager->create(Filesystem::class); +$fs->getDirectoryWrite(DirectoryList::ROOT)->delete('dev/tests/functional/generated/'); // Generate factories for old end-to-end tests $magentoObjectManager->create(\Magento\Mtf\Util\Generate\Factory::class)->launch(); diff --git a/dev/tests/functional/utils/generate/factory.php b/dev/tests/functional/utils/generate/factory.php index d3af305ce1692..e3024c38ec357 100644 --- a/dev/tests/functional/utils/generate/factory.php +++ b/dev/tests/functional/utils/generate/factory.php @@ -1,6 +1,6 @@ + + + + + + + + diff --git a/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/zip_codes.xml b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/zip_codes.xml new file mode 100644 index 0000000000000..dc0ed7abf72b1 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/zip_codes.xml @@ -0,0 +1,20 @@ + + + + + + ^[0-9]{4}\s[a-zA-Z]{2}$ + ^[0-5]{4}[a-z]{2}$ + + + + + ^[0-2]{4}[A-Z]{2}$ + + + diff --git a/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/registration.php b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/registration.php new file mode 100644 index 0000000000000..02cf3dd74ed2b --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/registration.php @@ -0,0 +1,12 @@ +getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleDirectoryZipCodes') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleDirectoryZipCodes', __DIR__); +} diff --git a/dev/tests/integration/_files/Magento/TestModuleSample/composer.json b/dev/tests/integration/_files/Magento/TestModuleSample/composer.json index 4d6383045d27f..3e8e5650b85a7 100644 --- a/dev/tests/integration/_files/Magento/TestModuleSample/composer.json +++ b/dev/tests/integration/_files/Magento/TestModuleSample/composer.json @@ -2,7 +2,7 @@ "name": "magento/module-sample-test", "description": "test sample module", "require": { - "php": "~5.6.0|7.0.2|7.0.4|~7.0.6", + "php": "~5.6.5|7.0.2|7.0.4|~7.0.6", "magento/framework": "100.1.*", "magento/module-integration": "100.1.*" }, diff --git a/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml index 152fd86216908..103ace949994c 100644 --- a/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml +++ b/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/_files/Magento/TestModuleSample/registration.php b/dev/tests/integration/_files/Magento/TestModuleSample/registration.php index 8f573474f7516..81b83d6b706c2 100644 --- a/dev/tests/integration/_files/Magento/TestModuleSample/registration.php +++ b/dev/tests/integration/_files/Magento/TestModuleSample/registration.php @@ -1,6 +1,6 @@ \Magento\TestFramework\View\Layout::class, \Magento\Framework\App\ResourceConnection\ConnectionAdapterInterface::class => \Magento\TestFramework\Db\ConnectionAdapter::class, - \Magento\Framework\Filesystem\DriverInterface::class => \Magento\Framework\Filesystem\Driver\File::class + \Magento\Framework\Filesystem\DriverInterface::class => \Magento\Framework\Filesystem\Driver\File::class, + \Magento\Framework\App\Config\ScopeConfigInterface::class => \Magento\TestFramework\App\Config::class, ]; diff --git a/dev/tests/integration/etc/install-config-mysql.php.dist b/dev/tests/integration/etc/install-config-mysql.php.dist index 6fffcb22b5000..0a6460a898b0c 100644 --- a/dev/tests/integration/etc/install-config-mysql.php.dist +++ b/dev/tests/integration/etc/install-config-mysql.php.dist @@ -1,6 +1,6 @@ get( - \Magento\Backend\App\ConfigInterface::class + \Magento\Framework\App\Config\MutableScopeConfigInterface::class )->getValue( $configPath ); @@ -49,7 +54,7 @@ protected function _getConfigValue($configPath) protected function _setConfigValue($configPath, $value) { \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Backend\App\ConfigInterface::class + \Magento\Framework\App\Config\MutableScopeConfigInterface::class )->setValue( $configPath, $value diff --git a/dev/tests/integration/framework/Magento/TestFramework/Annotation/AppArea.php b/dev/tests/integration/framework/Magento/TestFramework/Annotation/AppArea.php index c5a626433505b..4e1c8eea75847 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Annotation/AppArea.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Annotation/AppArea.php @@ -1,6 +1,6 @@ data[$configType] = new DataObject($data); + } + + /** + * Retrieve Scope Code Resolver + * + * @return ScopeCodeResolver + */ + private function getScopeCodeResolver() + { + if (!$this->scopeCodeResolver) { + $this->scopeCodeResolver = ObjectManager::getInstance()->get(ScopeCodeResolver::class); + } + + return $this->scopeCodeResolver; + } + + /** + * Set config value in the corresponding config scope + * + * @param string $path + * @param mixed $value + * @param string $scope + * @param null|string $scopeCode + * @return void + */ + public function setValue( + $path, + $value, + $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + $scopeCode = null + ) { + $result = $this->get('system'); + + if ($scope === 'store') { + $scope = 'stores'; + } elseif ($scope === 'website') { + $scope = 'websites'; + } + + if (empty($scopeCode)) { + $scopeCode = $this->getScopeCodeResolver()->resolve($scope, $scopeCode); + } + + $keys = explode('/', $path); + if ($scope !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + $searchKeys = array_merge([$scope, $scopeCode], $keys); + } else { + $searchKeys = array_merge([$scope], $keys); + } + + $this->updateResult($searchKeys, $result, $value); + $this->setData($result, 'system'); + } + + /** + * Recursively update results in global variable, which hold configs + * + * @param array $keys + * @param array $result + * @param mixed $value + * @return void + */ + private function updateResult(array $keys, & $result, $value) + { + $key = array_shift($keys); + + if (empty($keys)) { + $result[$key] = $value; + } else { + $this->updateResult($keys, $result[$key], $value); + } + } + + /** + * Flush all muted settings + * + * @return void + */ + public function clean() + { + $this->data = null; + $this->scopeCodeResolver = null; + parent::clean(); + } + + /** + * @inheritdoc + */ + public function get($configType, $path = null, $default = null) + { + $path = $path === null ? '' : $path; + if (!isset($this->data[$configType]) || $this->data[$configType]->getData($path) === null) { + return parent::get($configType, $path, $default); + } + + return $this->data[$configType]->getData($path); + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/App/EnvironmentFactory.php b/dev/tests/integration/framework/Magento/TestFramework/App/EnvironmentFactory.php index f044d48d54948..f84f8cc4cae82 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/App/EnvironmentFactory.php +++ b/dev/tests/integration/framework/Magento/TestFramework/App/EnvironmentFactory.php @@ -1,6 +1,6 @@ getTestAppConfig()->isSetFlag($path, $scopeType, $scopeCode); + } + + /** + * @inheritdoc + */ + public function getValue($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + { + return $this->getTestAppConfig()->getValue($path, $scopeType, $scopeCode); + } + + /** + * @inheritdoc + */ + public function setValue( + $path, + $value, + $scopeType = \Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + $scopeCode = null + ) { + return $this->getTestAppConfig()->setValue($path, $value, $scopeType, $scopeCode); + } + + /** + * Clean app config cache + * + * @param string|null $type + * @return void + */ + public function clean() + { + $this->getTestAppConfig()->clean(); + } + + /** + * Retrieve test app config instance + * + * @return \Magento\TestFramework\App\Config + */ + private function getTestAppConfig() + { + if (!$this->testAppConfig) { + $this->testAppConfig = ObjectManager::getInstance()->get(ScopeConfigInterface::class); + } + + return $this->testAppConfig; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/App/ObjectManager/Environment/Developer.php b/dev/tests/integration/framework/Magento/TestFramework/App/ObjectManager/Environment/Developer.php index 0c75927a04e27..d777fc683dbce 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/App/ObjectManager/Environment/Developer.php +++ b/dev/tests/integration/framework/Magento/TestFramework/App/ObjectManager/Environment/Developer.php @@ -1,6 +1,6 @@ getTestScopeConfig()->clean(); + return $this; + } + + /** + * Retrieve Test Scope Config + * + * @return Config + */ + public function getTestScopeConfig() + { + if (!$this->testAppConfig) { + $this->testAppConfig = ObjectManager::getInstance()->get(Config::class); + } + + return $this->testAppConfig; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/App/State.php b/dev/tests/integration/framework/Magento/TestFramework/App/State.php index 411b7a612a01a..8ed4ffbc24be0 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/App/State.php +++ b/dev/tests/integration/framework/Magento/TestFramework/App/State.php @@ -1,6 +1,6 @@ clearCache(); - \Magento\Framework\Data\Form::setElementRenderer(null); \Magento\Framework\Data\Form::setFieldsetRenderer(null); \Magento\Framework\Data\Form::setFieldsetElementRenderer(null); @@ -633,12 +630,13 @@ protected function getCustomDirs() { $path = DirectoryList::PATH; $var = "{$this->installDir}/var"; + $generated = "{$this->installDir}/generated"; $customDirs = [ DirectoryList::CONFIG => [$path => "{$this->installDir}/etc"], DirectoryList::VAR_DIR => [$path => $var], DirectoryList::MEDIA => [$path => "{$this->installDir}/pub/media"], DirectoryList::STATIC_VIEW => [$path => "{$this->installDir}/pub/static"], - DirectoryList::GENERATION => [$path => "{$var}/generation"], + DirectoryList::GENERATED_CODE => [$path => "{$generated}/code"], DirectoryList::CACHE => [$path => "{$var}/cache"], DirectoryList::LOG => [$path => "{$var}/log"], DirectoryList::SESSION => [$path => "{$var}/session"], diff --git a/dev/tests/integration/framework/Magento/TestFramework/Backend/App/Config.php b/dev/tests/integration/framework/Magento/TestFramework/Backend/App/Config.php new file mode 100644 index 0000000000000..79c9bfc6823a6 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Backend/App/Config.php @@ -0,0 +1,46 @@ +mutableScopeConfig = $mutableScopeConfig; + } + + /** + * @inheritdoc + */ + public function setValue( + $path, + $value, + $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + $scopeCode = null + ) { + $this->mutableScopeConfig->setValue($path, $value, $scope, $scopeCode); + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Bootstrap.php b/dev/tests/integration/framework/Magento/TestFramework/Bootstrap.php index 81569125fd1b4..a92955b13237a 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Bootstrap.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Bootstrap.php @@ -1,6 +1,6 @@ _fixturesBaseDir), new \Magento\TestFramework\Event\Transaction( @@ -66,7 +68,8 @@ protected function _getSubscribers(\Magento\TestFramework\Application $applicati new \Magento\TestFramework\Annotation\ComponentRegistrarFixture($this->_fixturesBaseDir), new \Magento\TestFramework\Annotation\AppArea($application), new \Magento\TestFramework\Annotation\Cache($application), - new \Magento\TestFramework\Annotation\AdminConfigFixture() + new \Magento\TestFramework\Annotation\AdminConfigFixture(), + new \Magento\TestFramework\Annotation\ConfigFixture(), ]; } } diff --git a/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/Environment.php b/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/Environment.php index c4146d7fd3c90..7a6bd6a722f17 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/Environment.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Bootstrap/Environment.php @@ -1,6 +1,6 @@ get($cacheType)->getBackend()->clean(); + } + } + + /** + * Clean all cache + */ + public static function cleanAll() + { + $cachePool = self::getCachePool(); + foreach ($cachePool as $cacheType) { + $cacheType->getBackend()->clean(); + } + } + + /** + * Get cache pool + * + * @return Pool + */ + private static function getCachePool() + { + return Bootstrap::getObjectManager() + ->get(Pool::class); + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Helper/Config.php b/dev/tests/integration/framework/Magento/TestFramework/Helper/Config.php index a73b61c7359b8..f8eab8c72b639 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Helper/Config.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Helper/Config.php @@ -1,6 +1,6 @@ _originScopeScheme = $this->_scopePriorityScheme; } diff --git a/dev/tests/integration/framework/Magento/TestFramework/Isolation/AppConfig.php b/dev/tests/integration/framework/Magento/TestFramework/Isolation/AppConfig.php new file mode 100644 index 0000000000000..9c23bab8c3b10 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Isolation/AppConfig.php @@ -0,0 +1,50 @@ +getTestAppConfig()->clean(); + } + + /** + * Retrieve Test App Config + * + * @return Config + */ + private function getTestAppConfig() + { + if (!$this->testAppConfig) { + $this->testAppConfig = ObjectManager::getInstance()->get(Config::class); + } + + return $this->testAppConfig; + } +} diff --git a/dev/tests/integration/framework/Magento/TestFramework/Isolation/DeploymentConfig.php b/dev/tests/integration/framework/Magento/TestFramework/Isolation/DeploymentConfig.php index f6f73cc7d1bed..e3d10676db09d 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Isolation/DeploymentConfig.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Isolation/DeploymentConfig.php @@ -1,6 +1,6 @@ [ - \Magento\Framework\Stdlib\CookieManagerInterface::class => \Magento\TestFramework\CookieManager::class, - \Magento\Store\Model\StoreManagerInterface::class => \Magento\TestFramework\Store\StoreManager::class, + CookieManagerInterface::class => \Magento\TestFramework\CookieManager::class, + StoreManagerInterface::class => \Magento\TestFramework\Store\StoreManager::class, + ScopeConfigInterface::class => \Magento\TestFramework\App\Config::class, + \Magento\Framework\App\Config::class => \Magento\TestFramework\App\Config::class, + BackendConfig::class => \Magento\TestFramework\Backend\App\Config::class, + ReinitableConfig::class => \Magento\TestFramework\App\ReinitableConfig::class, + MutableScopeConfig::class => \Magento\TestFramework\App\MutableScopeConfig::class, ] ]; } diff --git a/dev/tests/integration/framework/Magento/TestFramework/ObjectManagerFactory.php b/dev/tests/integration/framework/Magento/TestFramework/ObjectManagerFactory.php index 8e2976b941fb8..1827d804c1693 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/ObjectManagerFactory.php +++ b/dev/tests/integration/framework/Magento/TestFramework/ObjectManagerFactory.php @@ -1,6 +1,6 @@ get(Config::class); + $reflection = new \ReflectionClass($testAppConfig); + $dataProperty = $reflection->getProperty('data'); + $dataProperty->setAccessible(true); + $savedConfig = $dataProperty->getValue($testAppConfig); + $this->decoratedStoreManager->reinitStores(); + + $dataProperty->setValue($testAppConfig, $savedConfig); $this->dispatchInitCurrentStoreAfterEvent(); } diff --git a/dev/tests/integration/framework/Magento/TestFramework/TestCase/AbstractBackendController.php b/dev/tests/integration/framework/Magento/TestFramework/TestCase/AbstractBackendController.php index 6fbd25fc23297..554faac046d3c 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/TestCase/AbstractBackendController.php +++ b/dev/tests/integration/framework/Magento/TestFramework/TestCase/AbstractBackendController.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/AdminConfigFixtureTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/AdminConfigFixtureTest.php index 67dc261b4b46b..d63fee073b915 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/AdminConfigFixtureTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Annotation/AdminConfigFixtureTest.php @@ -1,6 +1,6 @@ getMockBuilder(ScopeCodeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->model = new Config($scopeCodeResolver); + } + + public function testGet() + { + $configType = "system"; + $path = "stores/one"; + $value = 1; + $this->model->setValue($path, $value, 'default', 'one'); + + $this->assertEquals($value, $this->model->get($configType, 'default/stores/one')); + } + + public function testClean() + { + $configType = "system"; + $path = "stores/one"; + $value = 1; + $this->model->setValue($path, $value, 'default', 'one'); + $this->assertEquals($value, $this->model->get($configType, 'default/stores/one')); + $this->model->clean(); + $this->assertNull($this->model->get($configType, 'default/stores/one')); + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php index a2a2e862170e3..2d549a03abdc1 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/1.xml.dist b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/1.xml.dist index afc3b323b6981..a6549e4734655 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/1.xml.dist +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/1.xml.dist @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/2.xml b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/2.xml index fa974f7de05fb..5f8b8236928ec 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/2.xml +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/2.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/3.xml.dist b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/3.xml.dist index eaec5f1f63552..57e8031a78273 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/3.xml.dist +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/3.xml.dist @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/4.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/4.php index 84768e3b2a908..a6412b64c469c 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/4.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Bootstrap/_files/4.php @@ -1,6 +1,6 @@ model = new \Magento\TestFramework\Isolation\AppConfig(); + } + + protected function tearDown() + { + $this->model = null; + } + + public function testStartTestEndTest() + { + $test = $this->getMockBuilder(\PHPUnit_Framework_TestCase::class) + ->disableOriginalConstructor() + ->getMock(); + $modelReflection = new \ReflectionClass($this->model); + $testAppConfigProperty = $modelReflection->getProperty('testAppConfig'); + $testAppConfigProperty->setAccessible(true); + $testAppConfigMock = $this->getMockBuilder(\Magento\TestFramework\App\Config::class) + ->disableOriginalConstructor() + ->getMock(); + $testAppConfigProperty->setValue($this->model, $testAppConfigMock); + $testAppConfigMock->expects($this->once()) + ->method('clean'); + $this->model->startTest($test); + } +} diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Isolation/WorkingDirectoryTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Isolation/WorkingDirectoryTest.php index 5f63a2a5950c6..ee0ebd46c5aa2 100644 --- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Isolation/WorkingDirectoryTest.php +++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/Isolation/WorkingDirectoryTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/AdminNotification/Controller/Adminhtml/Notification/MarkAsReadTest.php b/dev/tests/integration/testsuite/Magento/AdminNotification/Controller/Adminhtml/Notification/MarkAsReadTest.php index 1dcfbca26fb7d..2c9a5f2be7004 100644 --- a/dev/tests/integration/testsuite/Magento/AdminNotification/Controller/Adminhtml/Notification/MarkAsReadTest.php +++ b/dev/tests/integration/testsuite/Magento/AdminNotification/Controller/Adminhtml/Notification/MarkAsReadTest.php @@ -1,6 +1,6 @@ exportData($csvfile); + $exportContent = $this->exportData($csvfile); + $this->assertDiscountTypes($exportContent); + $this->importData($csvfile); while ($index > 0) { @@ -72,6 +74,24 @@ public function testExport() } } + /** + * Assert for correct tier prices discount types. + * + * @param string $exportContent + * @return void + */ + private function assertDiscountTypes($exportContent) + { + $this->assertContains( + '2.0000,8.0000,Fixed', + $exportContent + ); + $this->assertContains( + '10.0000,50.00,Discount', + $exportContent + ); + } + /** * @magentoAppArea adminhtml * @magentoDbIsolation enabled diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php index e32939b195b7d..7a0a9ced2e9f6 100644 --- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php +++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricingTest.php @@ -1,6 +1,6 @@ \Magento\Customer\Model\Group::CUST_GROUP_ALL, 'value' => '300.0000', - 'qty' => '10.0000' + 'qty' => '10.0000', + 'percentage_value' => null ], [ 'customer_group_id' => '1', 'value' => '11.0000', - 'qty' => '11.0000' + 'qty' => '11.0000', + 'percentage_value' => null ], [ 'customer_group_id' => '3', 'value' => '14.0000', - 'qty' => '14.0000' + 'qty' => '14.0000', + 'percentage_value' => null + ], + [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'value' => '160.5000', + 'qty' => '20.0000', + 'percentage_value' => '50.0000' ] ], 'AdvancedPricingSimple 2' => [ [ 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, 'value' => '1000000.0000', - 'qty' => '100.0000' + 'qty' => '100.0000', + 'percentage_value' => null ], [ 'customer_group_id' => '0', 'value' => '12.0000', - 'qty' => '12.0000' + 'qty' => '12.0000', + 'percentage_value' => null ], [ 'customer_group_id' => '2', 'value' => '13.0000', - 'qty' => '13.0000' + 'qty' => '13.0000', + 'percentage_value' => null + ], + [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'value' => '327.0000', + 'qty' => '200.0000', + 'percentage_value' => '50.0000' ] ] ]; @@ -121,14 +139,40 @@ public function testImportAddUpdate() foreach ($productIdList as $sku => $productId) { $product->load($productId); $tierPriceCollection = $product->getTierPrices(); - $this->assertEquals(3, count($tierPriceCollection)); + $this->assertEquals(4, count($tierPriceCollection)); + $index = 0; /** @var \Magento\Catalog\Model\Product\TierPrice $tierPrice */ foreach ($tierPriceCollection as $tierPrice) { - $this->assertContains($tierPrice->getData(), $this->expectedTierPrice[$sku]); + $this->checkPercentageDiscount($tierPrice, $sku, $index); + $this->assertEquals(0, $tierPrice->getExtensionAttributes()->getWebsiteId()); + $tierPriceData = $tierPrice->getData(); + unset($tierPriceData['extension_attributes']); + $this->assertContains($tierPriceData, $this->expectedTierPrice[$sku]); + $index ++; } } } + /** + * Check percentage discount type. + * + * @param \Magento\Catalog\Model\Product\TierPrice $tierPrice + * @param string $sku + * @param int $index + * @return void + */ + private function checkPercentageDiscount( + \Magento\Catalog\Model\Product\TierPrice $tierPrice, + $sku, + $index + ) { + $this->assertEquals( + $this->expectedTierPrice[$sku][$index]['percentage_value'], + $tierPrice->getExtensionAttributes()->getPercentageValue() + ); + $tierPrice->setData('percentage_value', $tierPrice->getExtensionAttributes()->getPercentageValue()); + } + /** * @magentoAppArea adminhtml * @magentoDbIsolation enabled @@ -237,10 +281,16 @@ public function testImportReplace() foreach ($productIdList as $sku => $productId) { $product->load($productId); $tierPriceCollection = $product->getTierPrices(); - $this->assertEquals(3, count($tierPriceCollection)); + $this->assertEquals(4, count($tierPriceCollection)); + $index = 0; /** @var \Magento\Catalog\Model\Product\TierPrice $tierPrice */ foreach ($tierPriceCollection as $tierPrice) { - $this->assertContains($tierPrice->getData(), $this->expectedTierPrice[$sku]); + $this->checkPercentageDiscount($tierPrice, $sku, $index); + $this->assertEquals(0, $tierPrice->getExtensionAttributes()->getWebsiteId()); + $tierPriceData = $tierPrice->getData(); + unset($tierPriceData['extension_attributes']); + $this->assertContains($tierPriceData, $this->expectedTierPrice[$sku]); + $index ++; } } } diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/_files/import_advanced_pricing.csv b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/_files/import_advanced_pricing.csv index 37c0dff622f56..0c25cb37bf220 100644 --- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/_files/import_advanced_pricing.csv +++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/Model/Import/_files/import_advanced_pricing.csv @@ -1,7 +1,9 @@ -sku,tier_price_website,tier_price_customer_group,tier_price_qty,tier_price -"AdvancedPricingSimple 1","All Websites [USD]","ALL GROUPS",10.0000,300.0000 -"AdvancedPricingSimple 2","All Websites [USD]","ALL GROUPS",100.0000,1000000.0000 -"AdvancedPricingSimple 1","All Websites [USD]",General,11.0000,11.0000 -"AdvancedPricingSimple 2","All Websites [USD]","NOT LOGGED IN",12.0000,12.0000 -"AdvancedPricingSimple 1","All Websites [USD]",Retailer,14.0000,14.0000 -"AdvancedPricingSimple 2","All Websites [USD]",Wholesale,13.0000,13.0000 +sku,tier_price_website,tier_price_customer_group,tier_price_qty,tier_price,tier_price_value_type +"AdvancedPricingSimple 1","All Websites [USD]","ALL GROUPS",10.0000,300.0000,Fixed +"AdvancedPricingSimple 2","All Websites [USD]","ALL GROUPS",100.0000,1000000.0000,Fixed +"AdvancedPricingSimple 1","All Websites [USD]",General,11.0000,11.0000,Fixed +"AdvancedPricingSimple 2","All Websites [USD]","NOT LOGGED IN",12.0000,12.0000,Fixed +"AdvancedPricingSimple 1","All Websites [USD]",Retailer,14.0000,14.0000,Fixed +"AdvancedPricingSimple 2","All Websites [USD]",Wholesale,13.0000,13.0000,Fixed +"AdvancedPricingSimple 1","All Websites [USD]","ALL GROUPS",20.0000,50,Discount +"AdvancedPricingSimple 2","All Websites [USD]","ALL GROUPS",200.0000,50,Discount diff --git a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php index dddfcf4238591..0ad59e8787c8a 100644 --- a/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php +++ b/dev/tests/integration/testsuite/Magento/AdvancedPricingImportExport/_files/create_products.php @@ -1,6 +1,6 @@ _model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Authorization\Model\Rules::class ); + $this->user = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\User\Model\User::class + ); } /** @@ -55,7 +63,9 @@ public function testInitialUserPermissions() public function testSetAllowForAllResources() { $resources = ['Magento_Backend::all']; - $this->_model->setRoleId(1)->setResources($resources)->saveRel(); + $this->user->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); + $roleId = $this->user->getRole()->getRoleId(); + $this->_model->setRoleId($roleId)->setResources($resources)->saveRel(); $expectedPermissions = ['Magento_Backend::all']; $this->_checkExistingPermissions($expectedPermissions); } @@ -66,10 +76,13 @@ public function testSetAllowForAllResources() protected function _checkExistingPermissions($expectedDefaultPermissions) { $connection = $this->_model->getResource()->getConnection(); - $ruleSelect = $connection->select()->from($this->_model->getResource()->getMainTable()); + $this->user->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); + $roleId = $this->user->getRole()->getRoleId(); + $ruleSelect = $connection->select() + ->from($this->_model->getResource()->getMainTable()) + ->where('role_id = ?', $roleId); $rules = $ruleSelect->query()->fetchAll(); - $this->assertEquals(1, count($rules)); $actualPermissions = []; foreach ($rules as $rule) { $actualPermissions[] = $rule['resource_id']; diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/PlaceTest.php b/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/PlaceTest.php index ee671e3b00821..ccc3993307140 100644 --- a/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/PlaceTest.php +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Adminhtml/Authorizenet/Directpost/Payment/PlaceTest.php @@ -1,6 +1,6 @@ getRequest()->setControllerName( + $controllerName + )->setControllerModule( + $controllerModule + )->setActionName( + $controllerAction + )->setRouteName( + $controllerModule + )->setRequestUri("/{$controllerModule}/{$controllerName}/{$controllerAction}") + ->setParams($params); + + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** @var \Magento\Authorizenet\Controller\Directpost\Payment\Response */ + $controller = $objectManager->create(\Magento\Authorizenet\Controller\Directpost\Payment\Response::class); + + $response = $controller->execute(); + $output = $response->getLayout()->getOutput(); + + $expectedString = "{$controllerModule}/{$controllerName}/redirect/x_invoice_num/{$params['x_invoice_num']}/" + . "success/0/error_msg/{$errorMsg}/controller_action_name/{$controllerName}/"; + + $this->assertContains('window.location', $output); + $this->assertContains($expectedString, $output); + } + + /** + * Tests the controller for created blocks used for sending emails that should not affect layout response + * + * @param string $hash + * @param string[] $params + * + * @dataProvider responseActionAuthorizeCaptureSuccessDataProvider + */ + public function testBlockCreationAffectingResult($hash, $params) + { + $controllerName = 'directpost_payment'; + $controllerModule = 'authorizenet'; + $controllerAction = 'response'; + $params['x_invoice_num'] = 100000002; + $params['x_MD5_Hash'] = $hash; + $this->getRequest()->setControllerName( + $controllerName + )->setControllerModule( + $controllerModule + )->setActionName( + $controllerAction + )->setRouteName( + $controllerModule + )->setRequestUri("/{$controllerModule}/{$controllerName}/{$controllerAction}") + ->setParams($params); + + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $directpostMock = $this->getMockBuilder(\Magento\Authorizenet\Model\Directpost::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) + ->setMethods(['create']) + ->getMockForAbstractClass(); + $objectManagerMock->expects($this->atLeastOnce()) + ->method('create') + ->with(\Magento\Authorizenet\Model\Directpost::class) + ->willReturn($directpostMock); + $context = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Backend\App\Action\Context::class, + [ + 'objectManager' => $objectManagerMock + ] + ); + + /** @var \Magento\Authorizenet\Controller\Directpost\Payment\Response $controller */ + $controller = $objectManager->create( + \Magento\Authorizenet\Controller\Directpost\Payment\Response::class, + [ + 'context' => $context + ] + ); + + // create one block for potential layout stack modification that should not affect response + /** @var \Magento\Authorizenet\Block\Adminhtml\Order\View\Info\FraudDetails $block */ + $block = $objectManager->get(\Magento\Framework\View\LayoutInterface::class) + ->createBlock(\Magento\Authorizenet\Block\Adminhtml\Order\View\Info\FraudDetails::class); + $block->setTemplate('Magento_Payment::order/view/info/fraud_details.phtml'); + + $response = $controller->execute(); + $output = $response->getLayout()->getOutput(); + + $expectedString = "{$controllerModule}/{$controllerName}/redirect/x_invoice_num/{$params['x_invoice_num']}/" + . "success/1/controller_action_name/{$controllerName}/"; + + $this->assertContains('window.location', $output); + $this->assertContains($expectedString, $output); + } + + /** + * @return array + */ + public function responseActionAuthorizeCaptureDeclineDataProvider() + { + $postArray = [ + 'x_response_code' => 1, + 'x_response_reason_code' => 1, + 'x_response_reason_text' => 'This transaction has been approved.', + 'x_avs_code' => 'Y', + 'x_auth_code' => 'G0L0XR', + 'x_trans_id' => '60016479791', + 'x_method' => 'CC', + 'x_card_type' => 'American Express', + 'x_account_number' => 'XXXX0002', + 'x_first_name' => 'Name', + 'x_last_name' => 'Surname', + 'x_company' => null, + 'x_address' => 'Address', + 'x_city' => 'Austin', + 'x_state' => 'Texas', + 'x_zip' => '78753', + 'x_country' => 'US', + 'x_phone' => '5127242323', + 'x_fax' => null, + 'x_email' => 'customer@example.com', + 'x_description' => null, + 'x_type' => 'auth_capture', + 'x_cust_id' => null, + 'x_ship_to_first_name' => null, + 'x_ship_to_last_name' => null, + 'x_ship_to_company' => null, + 'x_ship_to_address' => null, + 'x_ship_to_city' => null, + 'x_ship_to_state' => null, + 'x_ship_to_zip' => null, + 'x_ship_to_country' => null, + 'x_amount' => 100.00, + 'x_tax' => 0.00, + 'x_duty' => 0.00, + 'x_freight' => 0.00, + 'x_tax_exempt' => false, + 'x_po_num' => null, + 'x_SHA2_Hash' => null, + 'x_cvv2_resp_code' => 'P', + 'x_cavv_response' => 2, + 'x_test_request' => false, + 'controller_action_name' => 'directpost_payment', + 'is_secure' => null + ]; + return [ + 'error_hash' => [ + 'invoice_num' => '1231231', + 'x_MD5_Hash' => 'F9AE81A5DA36057D1312D71C904FCCF2', + 'error_msg' => 'The%20transaction%20was%20declined%20because%20the%20' + . 'response%20hash%20validation%20failed.', + 'post' => $postArray + ] + ]; + } + + /** + * @return array + */ + public function responseActionAuthorizeCaptureSuccessDataProvider() + { + $postArray = [ + 'x_response_code' => 1, + 'x_response_reason_code' => 1, + 'x_response_reason_text' => 'This transaction has been approved.', + 'x_avs_code' => 'Y', + 'x_auth_code' => 'G0L0XR', + 'x_trans_id' => '60016479791', + 'x_method' => 'CC', + 'x_card_type' => 'American Express', + 'x_account_number' => 'XXXX0002', + 'x_first_name' => 'Name', + 'x_last_name' => 'Surname', + 'x_company' => null, + 'x_address' => 'Address', + 'x_city' => 'Austin', + 'x_state' => 'Texas', + 'x_zip' => '78753', + 'x_country' => 'US', + 'x_phone' => '5127242323', + 'x_fax' => null, + 'x_email' => 'integrationtest@magento.com', + 'x_description' => null, + 'x_type' => 'auth_capture', + 'x_cust_id' => null, + 'x_ship_to_first_name' => null, + 'x_ship_to_last_name' => null, + 'x_ship_to_company' => null, + 'x_ship_to_address' => null, + 'x_ship_to_city' => null, + 'x_ship_to_state' => null, + 'x_ship_to_zip' => null, + 'x_ship_to_country' => null, + 'x_amount' => 120.15, + 'x_tax' => 0.00, + 'x_duty' => 0.00, + 'x_freight' => 0.00, + 'x_tax_exempt' => false, + 'x_po_num' => null, + 'x_SHA2_Hash' => null, + 'x_cvv2_resp_code' => 'P', + 'x_cavv_response' => 2, + 'x_test_request' => false, + 'controller_action_name' => 'directpost_payment', + 'is_secure' => null + ]; + return [ + 'success' => [ + 'x_MD5_Hash' => '35DCF749F7760193FB8254886E1D1522', + 'post' => $postArray + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/PaymentTest.php b/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/PaymentTest.php index 3ec174d5b550b..886d54b903fbd 100644 --- a/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/PaymentTest.php +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/Controller/Directpost/PaymentTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + + $this->order = $this->getOrder(); + $this->request = $this->objectManager->get(Request::class); + } + + /** + * @covers \Magento\Authorizenet\Model\Directpost\Request::setDataFromOrder + * @magentoDataFixture Magento/Authorizenet/_files/order.php + */ + public function testSetDataFromOrder() + { + $customerEmail = 'john.doe@example.com'; + $merchantEmail = 'merchant@example.com'; + + /** @var Directpost|MockObject $payment */ + $payment = $this->getMockBuilder(Directpost::class) + ->disableOriginalConstructor() + ->setMethods(['getConfigData']) + ->getMock(); + + $payment->expects(static::exactly(2)) + ->method('getConfigData') + ->willReturnMap([ + ['email_customer', null, $customerEmail], + ['merchant_email', null, $merchantEmail] + ]); + + $result = $this->request->setDataFromOrder($this->order, $payment); + + static::assertEquals('US', $result->getXCountry()); + static::assertEquals('UK', $result->getXShipToCountry()); + static::assertEquals($customerEmail, $result->getXEmailCustomer()); + static::assertEquals($merchantEmail, $result->getXMerchantEmail()); + } + + /** + * Get stored order + * @return Order + */ + private function getOrder() + { + /** @var FilterBuilder $filterBuilder */ + $filterBuilder = $this->objectManager->get(FilterBuilder::class); + $filters = [ + $filterBuilder->setField(OrderInterface::INCREMENT_ID) + ->setValue('100000002') + ->create() + ]; + + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilters($filters) + ->create(); + + $orderRepository = $this->objectManager->get(OrderRepositoryInterface::class); + $orders = $orderRepository->getList($searchCriteria) + ->getItems(); + + /** @var OrderInterface $order */ + return array_pop($orders); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php new file mode 100644 index 0000000000000..67f9b2b32ca2f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php @@ -0,0 +1,129 @@ +objectManager = Bootstrap::getObjectManager(); + + $this->httpClientFactory = $this->getMockBuilder(ZendClientFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->directPost = $this->objectManager->create(Directpost::class, [ + 'httpClientFactory' => $this->httpClientFactory + ]); + } + + /** + * @covers \Magento\Authorizenet\Model\Directpost::capture + * @magentoDataFixture Magento/Authorizenet/_files/order.php + */ + public function testCapture() + { + $amount = 120.15; + /** @var Payment $payment */ + $payment = $this->getPayment(); + $transactionId = '106235225'; + + /** @var ZendClient|MockObject $httpClient */ + $httpClient = $this->getMockBuilder(ZendClient::class) + ->disableOriginalConstructor() + ->setMethods(['setUri', 'setConfig', 'setParameterPost', 'setMethod', 'request']) + ->getMock(); + + $this->httpClientFactory->expects(static::once()) + ->method('create') + ->willReturn($httpClient); + + $response = $this->getMockBuilder(Zend_Http_Response::class) + ->disableOriginalConstructor() + ->setMethods(['getBody']) + ->getMock(); + $response->expects(static::once()) + ->method('getBody') + ->willReturn( + "1(~)1(~)1(~)This transaction has been approved.(~)AWZFTG(~)P(~){$transactionId}(~)100000002(~) + (~)120.15(~)CC(~)prior_auth_capture(~)(~)Anthony(~)Nealy(~)(~)Pearl St(~)Los Angeles(~)California + (~)10020(~)US(~)22-333-44(~)(~)customer@example.com(~)John(~)Doe(~) + (~)Bourne St(~)London(~)(~)DW23W(~)UK(~)0.00(~)(~){$amount}(~)(~) + (~)74B5D54ADFE98093A0FF6446(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)XXXX1111(~)Visa(~)(~)(~)(~)(~) + (~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)(~)" + ); + + $httpClient->expects(static::once()) + ->method('request') + ->willReturn($response); + + $this->directPost->capture($payment, $amount); + + static::assertEquals($transactionId, $payment->getTransactionId()); + static::assertFalse($payment->getIsTransactionClosed()); + static::assertEquals('US', $payment->getOrder()->getBillingAddress()->getCountryId()); + static::assertEquals('UK', $payment->getOrder()->getShippingAddress()->getCountryId()); + } + + /** + * Get order payment + * @return Payment + */ + private function getPayment() + { + /** @var FilterBuilder $filterBuilder */ + $filterBuilder = $this->objectManager->get(FilterBuilder::class); + $filters = [ + $filterBuilder->setField(OrderInterface::INCREMENT_ID) + ->setValue('100000002') + ->create() + ]; + + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilters($filters) + ->create(); + + $orderRepository = $this->objectManager->get(OrderRepositoryInterface::class); + $orders = $orderRepository->getList($searchCriteria) + ->getItems(); + + /** @var OrderInterface $order */ + $order = array_pop($orders); + return $order->getPayment(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/_files/order.php b/dev/tests/integration/testsuite/Magento/Authorizenet/_files/order.php new file mode 100644 index 0000000000000..0e60a6e915e89 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/_files/order.php @@ -0,0 +1,70 @@ +get(Payment::class); +$payment + ->setMethod('authorizenet_directpost') + ->setAnetTransType('AUTH_ONLY') + ->setBaseAmountAuthorized($amount) + ->setPoNumber('10101200'); + +/** @var Address\ $billingAddress */ +$billingAddress = $objectManager->create(Address::class, [ + 'data' => [ + 'firstname' => 'John', + 'lastname' => 'Doe', + 'email' => 'customer@example.com', + 'street' => 'Pearl St', + 'city' => 'Los Angeles', + 'region' => 'CA', + 'postcode' => '10020', + 'country_id' => 'US', + 'telephone' => '22-333-44', + 'address_type' => 'billing' + ] +]); + +$shippingAddress = $objectManager->create(Address::class, [ + 'data' => [ + 'firstname' => 'John', + 'lastname' => 'Doe', + 'email' => 'customer@example.com', + 'street' => 'Bourne St', + 'city' => 'London', + 'postcode' => 'DW23W', + 'country_id' => 'UK', + 'telephone' => '22-333-44', + 'address_type' => 'billing' + ] +]); + +/** @var Order $order */ +$order = $objectManager->create(Order::class); +$order->setIncrementId('100000002') + ->setQuoteId(2) + ->setIncrementId('100000002') + ->setBaseGrandTotal($amount) + ->setBaseCurrencyCode('USD') + ->setBaseTaxAmount($amount) + ->setBaseShippingAmount($amount) + ->setCustomerEmail('customer@example.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setPayment($payment); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Backend/App/AbstractActionTest.php b/dev/tests/integration/testsuite/Magento/Backend/App/AbstractActionTest.php index 72834f82e9e13..98d2509b68267 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/App/AbstractActionTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/App/AbstractActionTest.php @@ -1,6 +1,6 @@ configCacheType = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( @@ -35,15 +40,18 @@ protected function setUp() ); $this->configCacheType->save('', \Magento\Backend\Model\Menu\Config::CACHE_MENU_OBJECT); - $this->blockMenu = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Backend\Block\Menu::class - ); - $reflection = new \ReflectionClass(\Magento\Framework\Component\ComponentRegistrar::class); $paths = $reflection->getProperty('paths'); $paths->setAccessible(true); $this->backupRegistrar = $paths->getValue(); $paths->setAccessible(false); + + $this->menuConfig = $this->prepareMenuConfig(); + + $this->blockMenu = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Backend\Block\Menu::class, + ['menuConfig' => $this->menuConfig] + ); } /** @@ -51,8 +59,7 @@ protected function setUp() */ public function testRenderNavigation() { - $menuConfig = $this->prepareMenuConfig(); - $menuHtml = $this->blockMenu->renderNavigation($menuConfig->getMenu()); + $menuHtml = $this->blockMenu->renderNavigation($this->menuConfig->getMenu()); $menu = new \SimpleXMLElement($menuHtml); $item = $menu->xpath('/ul/li/a/span')[0]; diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Page/FooterTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Page/FooterTest.php index ae6cc09ee1c79..c84a0741eb91b 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Page/FooterTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Page/FooterTest.php @@ -1,6 +1,6 @@ assertGreaterThan(15, strlen($this->_block->getFormKey())); } - - /** - * @magentoAppArea adminhtml - * @covers \Magento\Backend\Block\Template::isOutputEnabled - * @magentoConfigFixture current_store advanced/modules_disable_output/dummy 1 - */ - public function testIsOutputEnabledTrue() - { - $this->_block->setData('module_name', 'dummy'); - $this->assertFalse($this->_block->isOutputEnabled('dummy')); - } - - /** - * @magentoAppArea adminhtml - * @covers \Magento\Backend\Block\Template::isOutputEnabled - * @magentoConfigFixture current_store advanced/modules_disable_output/dummy 0 - */ - public function testIsOutputEnabledFalse() - { - $this->_block->setData('module_name', 'dummy'); - $this->assertTrue($this->_block->isOutputEnabled('dummy')); - } } diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/ContainerTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/ContainerTest.php index 1c0f58a06f896..04536c2ca3def 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/ContainerTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/ContainerTest.php @@ -1,6 +1,6 @@ setText($expectedHtml); $this->assertEquals($expectedHtml, $block->getFormHtml()); } + + public function testPseudoConstruct() + { + /** @var $block \Magento\Backend\Block\Widget\Form\Container */ + $block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\View\LayoutInterface::class + )->createBlock( + \Magento\Backend\Block\Widget\Form\Container::class, + '', + [ + 'data' => [ + \Magento\Backend\Block\Widget\Container::PARAM_CONTROLLER => 'user', + \Magento\Backend\Block\Widget\Form\Container::PARAM_MODE => 'edit', + \Magento\Backend\Block\Widget\Form\Container::PARAM_BLOCK_GROUP => 'Magento_User' + ] + ] + ); + $this->assertInstanceOf(\Magento\User\Block\User\Edit\Form::class, $block->getChildBlock('form')); + } } diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/FormTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/FormTest.php index 54d0c7b155620..39bc4ee413ff1 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/FormTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/FormTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->origRenderer = Phrase::getRenderer(); + /** @var RendererInterface|PHPUnit_Framework_MockObject_MockObject $rendererMock */ + $rendererMock = $this->getMock(RendererInterface::class); + $rendererMock->expects($this->any()) + ->method('render') + ->willReturnCallback( + function ($input) { + return end($input) . ' translated'; + } + ); + Phrase::setRenderer($rendererMock); + } + + protected function tearDown() + { + Phrase::setRenderer($this->origRenderer); + } + + /** + * @param array $columnData + * @param array $rowData + * @param string $expected + * @dataProvider renderDataProvider + */ + public function testRender($columnData, $rowData, $expected) + { + /** @var Text $renderer */ + $renderer = $this->objectManager->create(Text::class); + /** @var Column $column */ + $column = $this->objectManager->create( + Column::class, + [ + 'data' => $columnData + ] + ); + /** @var DataObject $row */ + $row = $this->objectManager->create( + DataObject::class, + [ + 'data' => $rowData + ] + ); + $this->assertEquals( + $expected, + $renderer->setColumn($column)->render($row) + ); + } + + /** + * @return array + */ + public function renderDataProvider() + { + return [ + [ + [ + 'index' => 'title', + 'translate' => true + ], + [ + 'title' => 'String' + ], + 'String translated' + ], + [ + [ + 'index' => 'title' + ], + [ + 'title' => 'Doesn\'t need to be translated' + ], + 'Doesn't need to be translated' + ], + [ + [ + 'format' => '#$subscriber_id $customer_name ($subscriber_email)' + ], + [ + 'subscriber_id' => '10', + 'customer_name' => 'John Doe', + 'subscriber_email' => 'john@doe.com' + ], + '#10 John Doe (john@doe.com)' + ], + [ + [ + 'format' => '$customer_name, email: $subscriber_email', + 'translate' => true + ], + [ + 'customer_name' => 'John Doe', + 'subscriber_email' => 'john@doe.com' + ], + 'John Doe, email: john@doe.com translated' + ], + [ + [ + 'format' => 'String', + 'translate' => true + ], + [], + 'String translated' + ], + [ + [ + 'format' => 'Doesn\'t need to be translated' + ], + [], + 'Doesn't need to be translated' + ] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ColumnSetTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ColumnSetTest.php index 86847eddb2c04..2c12f1f8c9868 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ColumnSetTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ColumnSetTest.php @@ -1,6 +1,6 @@ markTestIncomplete('MAGETWO-6406'); - parent::setUp(); - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->mageMode = $this->objectManager->get(State::class)->getMode(); + /** @var \Magento\Theme\Model\Theme\Registration $registration */ - $registration = $objectManager->get(\Magento\Theme\Model\Theme\Registration::class); + $registration = $this->objectManager->get(\Magento\Theme\Model\Theme\Registration::class); $registration->register(); - $objectManager->get(\Magento\Framework\View\DesignInterface::class)->setDesignTheme('BackendTest/test_default'); - $this->_layout = $objectManager->create( + $this->objectManager->get(\Magento\Framework\View\DesignInterface::class) + ->setDesignTheme('BackendTest/test_default'); + } + + protected function tearDown() + { + $this->objectManager->get(State::class)->setMode($this->mageMode); + } + + /** + * @param string $mageMode + */ + private function loadLayout($mageMode = State::MODE_DEVELOPER) + { + $this->objectManager->get(State::class)->setMode($mageMode); + $this->_layout = $this->objectManager->create( \Magento\Framework\View\LayoutInterface::class, ['area' => 'adminhtml'] ); @@ -48,20 +72,14 @@ protected function setUp() $this->assertNotFalse($this->_block, 'Could not load the block for testing'); } - /** - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getItems - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getCount - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::getItemsJson - * @covers \Magento\Backend\Block\Widget\Grid\Massaction::isAvailable - */ public function testMassactionDefaultValues() { + $this->loadLayout(); + /** @var $blockEmpty \Magento\Backend\Block\Widget\Grid\Massaction */ - $blockEmpty = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\View\LayoutInterface::class - )->createBlock( - \Magento\Backend\Block\Widget\Grid\Massaction::class - ); + $blockEmpty = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\View\LayoutInterface::class) + ->createBlock(\Magento\Backend\Block\Widget\Grid\Massaction::class); $this->assertEmpty($blockEmpty->getItems()); $this->assertEquals(0, $blockEmpty->getCount()); $this->assertSame('[]', $blockEmpty->getItemsJson()); @@ -71,6 +89,8 @@ public function testMassactionDefaultValues() public function testGetJavaScript() { + $this->loadLayout(); + $javascript = $this->_block->getJavaScript(); $expectedItemFirst = '#"option_id1":{"label":"Option One",' . @@ -86,6 +106,8 @@ public function testGetJavaScript() public function testGetJavaScriptWithAddedItem() { + $this->loadLayout(); + $input = [ 'id' => 'option_id3', 'label' => 'Option Three', @@ -100,20 +122,49 @@ public function testGetJavaScriptWithAddedItem() $this->assertRegExp($expected, $this->_block->getJavaScript()); } - public function testGetCount() + /** + * @param string $mageMode + * @param int $expectedCount + * @dataProvider getCountDataProvider + */ + public function testGetCount($mageMode, $expectedCount) { - $this->assertEquals(2, $this->_block->getCount()); + $this->loadLayout($mageMode); + $this->assertEquals($expectedCount, $this->_block->getCount()); + } + + /** + * @return array + */ + public function getCountDataProvider() + { + return [ + [ + 'mageMode' => State::MODE_DEVELOPER, + 'expectedCount' => 3, + ], + [ + 'mageMode' => State::MODE_DEFAULT, + 'expectedCount' => 3, + ], + [ + 'mageMode' => State::MODE_PRODUCTION, + 'expectedCount' => 2, + ], + ]; } /** - * @param $itemId - * @param $expectedItem + * @param string $itemId + * @param array $expectedItem * @dataProvider getItemsDataProvider */ public function testGetItems($itemId, $expectedItem) { + $this->loadLayout(); + $items = $this->_block->getItems(); - $this->assertCount(2, $items); + $this->assertCount(3, $items); $this->assertArrayHasKey($itemId, $items); $actualItem = $items[$itemId]; @@ -149,19 +200,29 @@ public function getItemsDataProvider() 'selected' => false, 'blockname' => '' ] + ], + [ + 'option_id3', + [ + 'id' => 'option_id3', + 'label' => 'Option Three', + 'url' => '#http:\/\/localhost\/index\.php\/(?:key\/([\w\d]+)\/)?#', + 'selected' => false, + 'blockname' => '' + ] ] ]; } public function testGridContainsMassactionColumn() { + $this->loadLayout(); $this->_layout->getBlock('admin.test.grid')->toHtml(); - $gridMassactionColumn = $this->_layout->getBlock( - 'admin.test.grid' - )->getColumnSet()->getChildBlock( - 'massaction' - ); + $gridMassactionColumn = $this->_layout->getBlock('admin.test.grid') + ->getColumnSet() + ->getChildBlock('massaction'); + $this->assertNotNull($gridMassactionColumn, 'Massaction column does not exist in the grid column set'); $this->assertInstanceOf( \Magento\Backend\Block\Widget\Grid\Column::class, diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/GridTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/GridTest.php index 4a08e9ce4e096..e7660d6631adb 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/GridTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/GridTest.php @@ -1,6 +1,6 @@ - + - Magento\Framework\Data\Collection + Magento\Framework\Data\Collection - - + + -
    Product name 1
    - product_name - text + Product name 1 + product_name + product_name + text
    - + -
    User Description
    - description - text + User Description + description + description + text
    - + -
    Qty
    - qty - number - 60px + Qty + qty + qty + number + 60
    - + -
    Date Added
    - added_at - 1 - date + Date Added + added_at + added_at + date + 1
    - + - test_id - test_id - test - 1 - - - - */*/option1 - Test - - - - */*/option2 - Are you sure? - - + test_id + test_id + 1 + + + Option One + */*/option1 + Test + + + Option Two + */*/option2 + Are you sure? + + + Option Three + */*/option3 + Magento\Backend\Block\Cache\Grid\Massaction\ProductionModeVisibilityChecker + + diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/registration.php b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/registration.php index 585c7763d4d07..bf6f22d903a03 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/design/adminhtml/Magento/test_default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/form_key_disabled.php b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/form_key_disabled.php index d22c42be44cfa..4fbcc496d272b 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/_files/form_key_disabled.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/_files/form_key_disabled.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/AuthTest.php b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/AuthTest.php index 3cd95cb69c265..ac9b4f96379b9 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/AuthTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/AuthTest.php @@ -1,6 +1,6 @@ get(State::CACHE_KEY); } + protected function setUp() + { + parent::setUp(); + $this->mageState = Bootstrap::getObjectManager()->get(AppState::class)->getMode(); + } + protected function tearDown() { + Bootstrap::getObjectManager()->get(AppState::class)->setMode($this->mageState); /** @var $cacheState \Magento\Framework\App\Cache\StateInterface */ $cacheState = Bootstrap::getObjectManager()->get(\Magento\Framework\App\Cache\StateInterface::class); foreach (self::$typesConfig as $type => $value) { @@ -42,7 +54,7 @@ protected function tearDown() * @dataProvider massActionsDataProvider * @param array $typesToEnable */ - public function testMassEnableAction($typesToEnable = []) + public function testMassEnableActionDeveloperMode($typesToEnable = []) { $this->setAll(false); @@ -53,16 +65,33 @@ public function testMassEnableAction($typesToEnable = []) if (in_array($cacheType, $typesToEnable)) { $this->assertEquals(1, $cacheState, "Type '{$cacheType}' has not been enabled"); } else { - $this->assertEquals(0, $cacheState, "Type '{$cacheType}' has not been enabled"); + $this->assertEquals(0, $cacheState, "Type '{$cacheType}' must remain disabled"); } } } + /** + * @dataProvider massActionsDataProvider + * @param array $typesToEnable + */ + public function testMassEnableActionProductionMode($typesToEnable = []) + { + Bootstrap::getObjectManager()->get(AppState::class)->setMode(AppState::MODE_PRODUCTION); + $this->setAll(false); + + $this->getRequest()->setParams(['types' => $typesToEnable]); + $this->dispatch('backend/admin/cache/massEnable'); + + foreach ($this->getCacheStates() as $cacheType => $cacheState) { + $this->assertEquals(0, $cacheState, "Type '{$cacheType}' must remain disabled"); + } + } + /** * @dataProvider massActionsDataProvider * @param array $typesToDisable */ - public function testMassDisableAction($typesToDisable = []) + public function testMassDisableActionDeveloperMode($typesToDisable = []) { $this->setAll(true); @@ -78,6 +107,23 @@ public function testMassDisableAction($typesToDisable = []) } } + /** + * @dataProvider massActionsDataProvider + * @param array $typesToDisable + */ + public function testMassDisableActionProductionMode($typesToDisable = []) + { + Bootstrap::getObjectManager()->get(AppState::class)->setMode(AppState::MODE_PRODUCTION); + $this->setAll(true); + + $this->getRequest()->setParams(['types' => $typesToDisable]); + $this->dispatch('backend/admin/cache/massDisable'); + + foreach ($this->getCacheStates() as $cacheType => $cacheState) { + $this->assertEquals(1, $cacheState, "Type '{$cacheType}' must remain enabled"); + } + } + /** * Retrieve cache states (enabled/disabled) information * diff --git a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/CacheTest.php b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/CacheTest.php index 10f297cea6737..3f3d20f9641f0 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/CacheTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/CacheTest.php @@ -1,6 +1,6 @@ loadArea(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE); - $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Backend\Model\Auth::class); - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Config\ScopeInterface::class - )->setCurrentScope(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $this->objectManager->create(\Magento\Backend\Model\Auth::class); + $this->objectManager->get(\Magento\Framework\Config\ScopeInterface::class) + ->setCurrentScope(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE); } public function testMenuItemManipulation() { /* @var $menu \Magento\Backend\Model\Menu */ - $menu = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Backend\Model\Menu\Config::class - )->getMenu(); + $menu = $this->objectManager->create(\Magento\Backend\Model\Menu\Config::class)->getMenu(); /* @var $itemFactory \Magento\Backend\Model\Menu\Item\Factory */ - $itemFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Backend\Model\Menu\Item\Factory::class - ); + $itemFactory = $this->objectManager->create(\Magento\Backend\Model\Menu\Item\Factory::class); // Add new item in top level $menu->add( @@ -52,7 +50,7 @@ public function testMenuItemManipulation() ) ); - //Add submenu + // Add submenu $menu->add( $itemFactory->create( [ @@ -79,4 +77,102 @@ public function testMenuItemManipulation() // Move menu item $menu->move('Magento_Catalog::catalog_products', 'Magento_Backend::system2'); } + + /** + * @magentoAppIsolation enabled + */ + public function testSerialize() + { + /** @var Menu $menu */ + $menu = $this->objectManager->get(\Magento\Backend\Model\MenuFactory::class)->create(); + /* @var \Magento\Backend\Model\Menu\Item\Factory $itemFactory */ + $itemFactory = $this->objectManager->create(\Magento\Backend\Model\Menu\Item\Factory::class); + + // Add new item in top level + $menu->add( + $itemFactory->create( + [ + 'id' => 'Magento_Backend::system3', + 'title' => 'Extended System', + 'module' => 'Magento_Backend', + 'resource' => 'Magento_Backend::system3', + ] + ) + ); + + // Add submenu + $menu->add( + $itemFactory->create( + [ + 'id' => 'Magento_Backend::system3_acl', + 'title' => 'Acl', + 'module' => 'Magento_Backend', + 'action' => 'admin/backend/acl/index', + 'resource' => 'Magento_Backend::system3_acl', + ] + ), + 'Magento_Backend::system3' + ); + $serializedString = $menu->serialize(); + $expected = '[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,"depends_on_config":null,' + . '"id":"Magento_Backend::system3","resource":"Magento_Backend::system3","path":"","action":null,' + . '"depends_on_module":null,"tooltip":"","title":"Extended System",' + . '"target":null,"sub_menu":[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,' + . '"depends_on_config":null,"id":"Magento_Backend::system3_acl","resource":"Magento_Backend::system3_acl",' + . '"path":"","action":"admin\/backend\/acl\/index","depends_on_module":null,"tooltip":"","title":"Acl",' + . '"target":null,"sub_menu":null}]}]'; + $this->assertEquals($expected, $serializedString); + } + + /** + * @magentoAppIsolation enabled + */ + public function testUnserialize() + { + $serializedMenu = '[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,' + . '"depends_on_config":null,"id":"Magento_Backend::system3","resource":"Magento_Backend::system3",' + . '"path":"","action":null,"depends_on_module":null,"tooltip":"","title":"Extended System",' + . '"target":null,"sub_menu":[{"parent_id":null,"module_name":"Magento_Backend","sort_index":null,' + . '"depends_on_config":null,"id":"Magento_Backend::system3_acl","resource":"Magento_Backend::system3_acl",' + . '"path":"","action":"admin\/backend\/acl\/index","depends_on_module":null,"tooltip":"","title":"Acl",' + . '"target":null,"sub_menu":null}]}]'; + /** @var Menu $menu */ + $menu = $this->objectManager->get(\Magento\Backend\Model\MenuFactory::class)->create(); + $menu->unserialize($serializedMenu); + $expected = [ + [ + 'parent_id' => null, + 'module_name' => 'Magento_Backend', + 'sort_index' => null, + 'depends_on_config' => null, + 'id' => 'Magento_Backend::system3', + 'resource' => 'Magento_Backend::system3', + 'path' => '', + 'action' => null, + 'depends_on_module' => null, + 'tooltip' => '', + 'title' => 'Extended System', + 'target' => null, + 'sub_menu' => + [ + [ + 'parent_id' => null, + 'module_name' => 'Magento_Backend', + 'sort_index' => null, + 'depends_on_config' => null, + 'id' => 'Magento_Backend::system3_acl', + 'resource' => 'Magento_Backend::system3_acl', + 'path' => '', + 'action' => 'admin/backend/acl/index', + 'depends_on_module' => null, + 'tooltip' => '', + 'title' => 'Acl', + 'sub_menu' => null, + 'target' => null + ], + ], + ], + ]; + $this->assertEquals($expected, $menu->toArray()); + } } diff --git a/dev/tests/integration/testsuite/Magento/Backend/Model/Search/CustomerTest.php b/dev/tests/integration/testsuite/Magento/Backend/Model/Search/CustomerTest.php index 6a75718dfe421..2745e9a228cf3 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Model/Search/CustomerTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Model/Search/CustomerTest.php @@ -1,6 +1,6 @@ get(\Magento\Framework\UrlInterface::class); $url->getUrl(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE . '/ajax/translate'); $this->_translateInline->processResponseBody($body, true); - $this->assertContains( - $url->getUrl(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE . '/ajax/translate'), - $body + $expected = str_replace( + [':', '/'], + ['\u003A', '\u002F'], + $url->getUrl(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE . '/ajax/translate') ); + $this->assertContains($expected, $body); } } diff --git a/dev/tests/integration/testsuite/Magento/Backend/Model/UrlTest.php b/dev/tests/integration/testsuite/Magento/Backend/Model/UrlTest.php index ee6d6a6c77551..f85c062a648b0 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Model/UrlTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Model/UrlTest.php @@ -1,6 +1,6 @@ config = $objectManager->create(Config::class, [ + 'methodCode' => self::METHOD_CODE + ]); + $this->systemConfig = $objectManager->create(SystemConfig::class); + } + + /** + * Test methods that load Braintree configuration, and verify that values were json decoded correctly + * by the serializer dependency. + * + * @magentoDbIsolation enabled + * @dataProvider countryCreditRetrievalProvider + * @param string $value + * @param array $expected + */ + public function testCountryCreditRetrieval($value, array $expected) + { + $this->systemConfig->setDataByPath('payment/' . self::METHOD_CODE . '/countrycreditcard', $value); + $this->systemConfig->save(); + + $countrySpecificCardTypeConfig = $this->config->getCountrySpecificCardTypeConfig(); + $this->assertEquals($expected, $countrySpecificCardTypeConfig); + + foreach ($expected as $country => $expectedCreditCardTypes) { + $countryAvailableCardTypes = $this->config->getCountryAvailableCardTypes($country); + $this->assertEquals($expectedCreditCardTypes, $countryAvailableCardTypes); + } + } + + public function countryCreditRetrievalProvider() + { + return [ + 'empty_array' => [ + 'value' => '[]', + 'expected' => [] + ], + 'valid_data' => [ + 'value' => '{"AF":["AE","VI"],"US":["AE","VI","MA"]}', + 'expected' => [ + 'AF' => ['AE', 'VI'], + 'US' => ['AE', 'VI', 'MA'] + ] + ] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Model/Adminhtml/System/Config/CountryCreditCardTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Model/Adminhtml/System/Config/CountryCreditCardTest.php new file mode 100644 index 0000000000000..6fa057a311a3f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/Model/Adminhtml/System/Config/CountryCreditCardTest.php @@ -0,0 +1,69 @@ +countryCreditCardConfig = $objectManager->get(CountryCreditCard::class); + $this->countryCreditCardConfig->setPath('payment/braintree/countrycreditcard'); + } + + /** + * Test save and load lifecycle of the Braintree configuration value. Save should trigger the passed + * array to be json encoded by the serializer. Load should trigger json decode of that value, and it + * should match what was originally passed in. + * + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + * @dataProvider saveAndLoadDataProvider + * @param array $value + * @param string $encodedExpectedValue + */ + public function testSaveAndLoad($value, $encodedExpectedValue) + { + $this->countryCreditCardConfig->setValue($value); + $this->countryCreditCardConfig->save(); + $this->assertEquals($encodedExpectedValue, $this->countryCreditCardConfig->getValue()); + + $this->countryCreditCardConfig->load($this->countryCreditCardConfig->getId()); + $loadedHashedArray = $this->countryCreditCardConfig->getValue(); + // strip the random hashes added by routine before assertion + $loadedIndexedArray = array_values($loadedHashedArray); + $this->assertEquals($value, $loadedIndexedArray); + } + + public function saveAndLoadDataProvider() + { + return [ + 'empty_array' => [ + 'value' => [], + 'expected' => '[]' + ], + 'valid_data' => [ + 'value' => [ + [ + 'country_id' => 'AF', + 'cc_types' => ['AE', 'VI'] + ], + [ + 'country_id' => 'US', + 'cc_types' => ['AE', 'VI', 'MA'] + ] + ], + 'expected' => '{"AF":["AE","VI"],"US":["AE","VI","MA"]}' + ] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Model/PaymentMethodListTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Model/PaymentMethodListTest.php new file mode 100644 index 0000000000000..7763a698f8d48 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/Model/PaymentMethodListTest.php @@ -0,0 +1,71 @@ +storeId = $objectManager->get(StoreManagerInterface::class) + ->getStore() + ->getId(); + $this->paymentMethodList = $objectManager->get(PaymentMethodListInterface::class); + } + + /** + * @magentoDataFixture Magento/Braintree/_files/payments.php + */ + public function testGetList() + { + $vaultPayments = $this->paymentMethodList->getList($this->storeId); + + static::assertNotEmpty($vaultPayments); + + $paymentCodes = array_map(function (VaultPaymentInterface $payment) { + return $payment->getCode(); + }, $vaultPayments); + + $expectedCodes = [ + PayPalConfigProvider::PAYPAL_VAULT_CODE, + ConfigProvider::CC_VAULT_CODE + ]; + static::assertNotEmpty(array_intersect($expectedCodes, $paymentCodes)); + } + + /** + * @magentoDataFixture Magento/Braintree/_files/payments.php + */ + public function testGetActiveList() + { + $vaultPayments = $this->paymentMethodList->getActiveList($this->storeId); + + static::assertNotEmpty($vaultPayments); + static::assertCount(1, $vaultPayments); + $payment = array_pop($vaultPayments); + static::assertEquals(PayPalConfigProvider::PAYPAL_VAULT_CODE, $payment->getCode()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php new file mode 100644 index 0000000000000..432240ebcd5b1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/Adminhtml/PayPal/TokenUiComponentProviderTest.php @@ -0,0 +1,62 @@ +objectManager = Bootstrap::getObjectManager(); + $this->tokenComponentProvider = $this->objectManager->get(TokenUiComponentProvider::class); + } + + /** + * @covers \Magento\Braintree\Model\Ui\Adminhtml\PayPal\TokenUiComponentProvider::getComponentForToken + * @magentoDataFixture Magento/Braintree/_files/paypal_vault_token.php + * @magentoAppArea adminhtml + */ + public function testGetComponentForToken() + { + $customerId = 1; + $token = 'mx29vk'; + $payerEmail = 'john.doe@example.com'; + + /** @var PaymentTokenManagement $tokenManagement */ + $tokenManagement = $this->objectManager->get(PaymentTokenManagement::class); + $paymentToken = $tokenManagement->getByGatewayToken($token, ConfigProvider::PAYPAL_CODE, $customerId); + + $component = $this->tokenComponentProvider->getComponentForToken($paymentToken); + $config = $component->getConfig(); + + static::assertNotEmpty($config[TokenUiComponentProviderInterface::COMPONENT_DETAILS]); + static::assertNotEmpty($config[TokenUiComponentProviderInterface::COMPONENT_PUBLIC_HASH]); + static::assertEquals(ConfigProvider::PAYPAL_VAULT_CODE, $config['code']); + + $details = $config[TokenUiComponentProviderInterface::COMPONENT_DETAILS]; + static::assertEquals($payerEmail, $details['payerEmail']); + static::assertNotEmpty($details['icon']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/TokensConfigProviderTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/TokensConfigProviderTest.php index b8550ae205429..2836149b8b511 100644 --- a/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/TokensConfigProviderTest.php +++ b/dev/tests/integration/testsuite/Magento/Braintree/Model/Ui/TokensConfigProviderTest.php @@ -1,6 +1,6 @@ objectManager->get(PaymentTokenManagement::class); $paymentToken = $tokenManagement->getByGatewayToken($token, PayPalConfigProvider::PAYPAL_CODE, $customerId); - $item = PayPalConfigProvider::PAYPAL_CODE . '_item_' . $paymentToken->getEntityId(); + $item = PayPalConfigProvider::PAYPAL_VAULT_CODE . '_' . $paymentToken->getEntityId(); /** @var Session $session */ $session = $this->objectManager->get(Session::class); diff --git a/dev/tests/integration/testsuite/Magento/Braintree/_files/fraud_order.php b/dev/tests/integration/testsuite/Magento/Braintree/_files/fraud_order.php index ebbce2682ce45..5258978a2ad7f 100644 --- a/dev/tests/integration/testsuite/Magento/Braintree/_files/fraud_order.php +++ b/dev/tests/integration/testsuite/Magento/Braintree/_files/fraud_order.php @@ -1,6 +1,6 @@ get(Config::class); +$config->setDataByPath('payment/' . ConfigProvider::PAYPAL_CODE . '/active', 1); +$config->save(); +$config->setDataByPath('payment/' . ConfigProvider::PAYPAL_VAULT_CODE . '/active', 1); +$config->save(); diff --git a/dev/tests/integration/testsuite/Magento/Braintree/_files/paypal_quote.php b/dev/tests/integration/testsuite/Magento/Braintree/_files/paypal_quote.php index b1a6d56d299e1..8e58a83af58bc 100644 --- a/dev/tests/integration/testsuite/Magento/Braintree/_files/paypal_quote.php +++ b/dev/tests/integration/testsuite/Magento/Braintree/_files/paypal_quote.php @@ -1,6 +1,6 @@ create(PaymentTokenRepository::class); -$tokenRepository->save($paymentToken); \ No newline at end of file +$tokenRepository->save($paymentToken); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/GridTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/GridTest.php index 7dfede8310a35..aac6d7ebe8e76 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/GridTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Bundle/Option/Search/GridTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + } + + /** + * Get test cases + * @return array + */ + abstract public function getTestCases(); + + /** + * @param array $strategyModifiers + * @param string $productSku + * @return void + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\StateException + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + protected function prepareFixture($strategyModifiers, $productSku) + { + $bundleProduct = $this->productRepository->get($productSku); + + foreach ($strategyModifiers as $modifier) { + if (method_exists($this, $modifier['modifierName'])) { + array_unshift($modifier['data'], $bundleProduct); + $bundleProduct = call_user_func_array([$this, $modifier['modifierName']], $modifier['data']); + } else { + throw new \Magento\Framework\Exception\InputException( + __('Modifier %s does not exists', $modifier['modifierName']) + ); + } + } + + $this->productRepository->save($bundleProduct); + } + + /** + * Add simple product to bundle + * + * @param \Magento\Catalog\Model\Product $bundleProduct + * @param array $optionsData + * @return \Magento\Catalog\Model\Product + */ + protected function addSimpleProduct(\Magento\Catalog\Model\Product $bundleProduct, array $optionsData) + { + $options = []; + + foreach ($optionsData as $optionData) { + $links = []; + $linksData = $optionData['links']; + unset($optionData['links']); + + $option = $this->objectManager->create(\Magento\Bundle\Api\Data\OptionInterfaceFactory::class) + ->create(['data' => $optionData]) + ->setSku($bundleProduct->getSku()); + + foreach ($linksData as $linkData) { + $links[] = $this->objectManager->create(\Magento\Bundle\Api\Data\LinkInterfaceFactory::class) + ->create(['data' => $linkData]); + } + + $option->setProductLinks($links); + $options[] = $option; + } + + $extension = $bundleProduct->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $bundleProduct->setExtensionAttributes($extension); + + return $bundleProduct; + } + + /** + * @param \Magento\Catalog\Model\Product $bundleProduct + * @param array $optionsData + * @return \Magento\Catalog\Model\Product + */ + protected function addCustomOption(\Magento\Catalog\Model\Product $bundleProduct, array $optionsData) + { + /** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory $customOptionFactory */ + $customOptionFactory = $this->objectManager + ->create(\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory::class); + + $options = []; + foreach ($optionsData as $optionData) { + $customOption = $customOptionFactory->create( + [ + 'data' => $optionData + ] + ); + $customOption->setProductSku($bundleProduct->getSku()); + $customOption->setOptionId(null); + + $options[] = $customOption; + } + + $bundleProduct->setOptions($options); + $bundleProduct->setCanSaveCustomOptions(true); + + return $bundleProduct; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorTest.php new file mode 100644 index 0000000000000..55f6d26f5a712 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundlePriceCalculatorTest.php @@ -0,0 +1,327 @@ +prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * @param array $strategyModifiers + * @param array $expectedResults + * @dataProvider getTestCases + * @magentoAppIsolation enabled + * @magentoConfigFixture current_store catalog/price/scope 1 + */ + public function testPriceForDynamicBundleInWebsiteScope(array $strategyModifiers, array $expectedResults) + { + $this->prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * Test cases for current test + * @return array + */ + public function getTestCases() + { + return [ + '#1 Testing price for dynamic bundle product with one simple' => [ + 'strategy' => $this->getBundleConfiguration1(), + 'expectedResults' => [ + // just price from simple1 + 'minimalPrice' => 10, + // just price from simple1 + 'maximalPrice' => 10 + ] + ], + + '#2 Testing price for dynamic bundle product with three simples and different qty' => [ + 'strategy' => $this->getBundleConfiguration2(), + 'expectedResults' => [ + // min price from simples 3*10 or 30 + 'minimalPrice' => 30, + // (3 * 10) + (2 * 20) + 30 + 'maximalPrice' => 100 + ] + ], + + '#3 Testing price for dynamic bundle product with four simples and different price' => [ + 'strategy' => $this->getBundleConfiguration3(), + 'expectedResults' => [ + // 10 + 'minimalPrice' => 10, + // 10 + 20 + 30 + 'maximalPrice' => 60 + ] + ], + + '#4 Testing price for dynamic bundle with two non required options' => [ + 'strategy' => $this->getBundleConfiguration4(), + 'expectedResults' => [ + // 1 * 10 + 'minimalPrice' => 10, + // 3 * 20 + 1 * 10 + 3 * 20 + 'maximalPrice' => 130 + ] + ], + + '#5 Testing price for dynamic bundle with two required options' => [ + 'strategy' => $this->getBundleConfiguration5(), + 'expectedResults' => [ + // 1 * 10 + 1 * 10 + 'minimalPrice' => 20, + // 3 * 20 + 1 * 10 + 3 * 20 + 'maximalPrice' => 130 + ] + ], + ]; + } + + /** + * Dynamic bundle product with one simple + * + * @return array + */ + private function getBundleConfiguration1() + { + $optionsData = [ + [ + 'title' => 'op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + ] + ], + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle product with three simples and different qty + * + * @return array + */ + private function getBundleConfiguration2() + { + $optionsData = [ + [ + 'title' => 'op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 3, + ], + [ + 'sku' => 'simple2', + 'qty' => 2, + ], + [ + 'sku' => 'simple3', + 'qty' => 1, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle product with three simples and different price + * + * @return array + */ + private function getBundleConfiguration3() + { + $optionsData = [ + [ + 'title' => 'op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 1, + ], + [ + 'sku' => 'simple3', + 'qty' => 1, + ] + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with two non required options and special price + * @return array + */ + private function getBundleConfiguration4() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => false, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => false, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with two required options + * @return array + */ + private function getBundleConfiguration5() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithCatalogPriceRuleCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithCatalogPriceRuleCalculatorTest.php new file mode 100644 index 0000000000000..65d02f77abf41 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithCatalogPriceRuleCalculatorTest.php @@ -0,0 +1,433 @@ +prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * Test cases for current test + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getTestCases() + { + return [ + '#1 Testing price for dynamic bundle with one required option' => [ + 'strategy' => $this->getBundleProductConfiguration1(), + 'expectedResults' => [ + // 10 * 0.9 + 'minimalPrice' => 9, + + // 10 * 0.9 + 'maximalPrice' => 9 + ] + ], + + '#3 Testing price for dynamic bundle with one non required option' => [ + 'strategy' => $this->getBundleProductConfiguration3(), + 'expectedResults' => [ + // 0.9 * 2 * 10 + 'minimalPrice' => 18, + + // 0.9 * 2 * 10 + 'maximalPrice' => 18 + ] + ], + + '#4 Testing price for dynamic bundle with one required checkbox type option and 2 simples' => [ + 'strategy' => $this->getBundleProductConfiguration4(), + 'expectedResults' => [ + // 0.9 * 1 * 10 + 'minimalPrice' => 9, + + // 0.9 * 1 * 10 + 3 * 0.9 * 20 + 'maximalPrice' => 63 + ] + ], + + '#5 Testing price for dynamic bundle with one required multi type option and 2 simples' => [ + 'strategy' => $this->getBundleProductConfiguration5(), + 'expectedResults' => [ + // 0.9 * 1 * 10 + 'minimalPrice' => 9, + + // 0.9 * 1 * 10 + 3 * 0.9 * 20 + 'maximalPrice' => 63 + ] + ], + + '#6 Testing price for dynamic bundle with one required radio type option and 2 simples' => [ + 'strategy' => $this->getBundleProductConfiguration6(), + 'expectedResults' => [ + // 0.9 * 1 * 10 + 'minimalPrice' => 9, + + // 0.9 * 3 * 20 + 'maximalPrice' => 54 + ] + ], + + '#7 Testing price for dynamic bundle with two required options' => [ + 'strategy' => $this->getBundleProductConfiguration7(), + 'expectedResults' => [ + // 0.9 * 1 * 10 + 0.9 * 1 * 10 + 'minimalPrice' => 18, + + // 3 * 0.9 * 20 + 1 * 0.9 * 10 + 3 * 0.9 * 20 + 'maximalPrice' => 117 + ] + ], + + '#8 Testing price for dynamic bundle with one required option and one non required' => [ + 'strategy' => $this->getBundleProductConfiguration8(), + 'expectedResults' => [ + // 1 * 0.9 * 10 + 'minimalPrice' => 9, + + // 3 * 0.9 * 20 + 1 * 0.9 * 10 + 3 * 0.9 * 20 + 'maximalPrice' => 117 + ] + ], + + '#9 Testing price for dynamic bundle with two non required options' => [ + 'strategy' => $this->getBundleProductConfiguration9(), + 'expectedResults' => [ + // 0.9 * 1 * 10 + 'minimalPrice' => 9, + + // 3 * 0.9 * 20 + 1 * 0.9 * 10 + 3 * 0.9 * 20 + 'maximalPrice' => 117 + ] + ], + ]; + } + + /** + * Dynamic bundle with one required option + * @return array + */ + private function getBundleProductConfiguration1() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + ] + ], + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one non required option + * @return array + */ + private function getBundleProductConfiguration3() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'type' => 'checkbox', + 'required' => false, + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 2, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required checkbox type option and 2 simples + * @return array + */ + private function getBundleProductConfiguration4() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'type' => 'checkbox', + 'required' => true, + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required multi type option and 2 simples + * @return array + */ + private function getBundleProductConfiguration5() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'multi', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required radio type option and 2 simples + * @return array + */ + private function getBundleProductConfiguration6() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with two required options + * @return array + */ + private function getBundleProductConfiguration7() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required option and one non required + * @return array + */ + private function getBundleProductConfiguration8() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => false, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with two non required options + * @return array + */ + private function getBundleProductConfiguration9() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => false, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => false, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithSpecialPriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithSpecialPriceCalculatorTest.php new file mode 100644 index 0000000000000..8c5b1fbfea734 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithSpecialPriceCalculatorTest.php @@ -0,0 +1,339 @@ +prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + + if (isset($expectedResults['regularMinimalPrice'])) { + $priceCode = \Magento\Catalog\Pricing\Price\RegularPrice::PRICE_CODE; + $this->assertEquals( + $expectedResults['regularMinimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal regular price on product' + ); + } + + if (isset($expectedResults['regularMaximalPrice'])) { + $priceCode = \Magento\Catalog\Pricing\Price\RegularPrice::PRICE_CODE; + $this->assertEquals( + $expectedResults['regularMaximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal regular price on product' + ); + } + } + + /** + * Test cases for current test + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getTestCases() + { + return [ + '#1 Testing price for dynamic bundle with one required option and special price' => [ + 'strategy' => $this->getBundleConfiguration1(), + 'expectedResults' => [ + // 0.5 * 10 + 'minimalPrice' => 5, + // 0.5 * 10 + 'maximalPrice' => 5 + ] + ], + + '#2 Testing price for dynamic bundle with one non required option and special price' => [ + 'strategy' => $this->getBundleConfiguration2(), + 'expectedResults' => [ + // 0.5 * 2 * 10 + 'minimalPrice' => 10, + // 0.5 * 2 * 10 + 'maximalPrice' => 10 + ] + ], + + ' + #3 Testing price for dynamic bundle + with one required checkbox type option, two simples and special price + ' => [ + 'strategy' => $this->getBundleConfiguration3(), + 'expectedResults' => [ + // 0.5 * 1 * 10 + 'minimalPrice' => 5, + // 0.5 * (1 * 10 + 3 * 30) + 'maximalPrice' => 50 + ] + ], + + ' + #4 Testing price for dynamic bundle + with one required multi type option, two simples with special price + ' => [ + 'strategy' => $this->getBundleConfiguration4(), + 'expectedResults' => [ + // 0.5 * (min (1 * 9.9, 2.5 * 4)) + 'minimalPrice' => 4.95, + // 0.5 * ( 1 * 9.9 + 2.5 * 4) + 'maximalPrice' => 9.95 + ] + ], + + '#5 Testing price for dynamic bundle with one required option, one non required and special price' => [ + 'strategy' => $this->getBundleConfiguration5(), + 'expectedResults' => [ + // 0.5 * (3 * 2.5) + 'minimalPrice' => 3.75, + // 0.5 * (3 * 13 + 1 * 30 + 1 * 10) + 'maximalPrice' => 39.5, + // 1 * 10 + 'regularMinimalPrice' => '10', + // 3 * 20 + (30 * 1 + 13 * 3) + 'regularMaximalPrice' => '129', + ] + ], + + '#6 Testing price for dynamic bundle with one simple product with special price' => [ + 'strategy' => $this->getBundleConfiguration6(), + 'expectedResults' => [ + // 0.5 * min(4 * 2.5, 1 * 9.9) + 'minimalPrice' => 4.95, + // 0.5 * max(4 * 2.5, 1 * 9.9) + 'maximalPrice' => 5 + ] + ], + ]; + } + + /** + * Dynamic bundle with one required option + * @return array + */ + private function getBundleConfiguration1() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one non required option and special price + * @return array + */ + private function getBundleConfiguration2() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'type' => 'checkbox', + 'required' => false, + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 2, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required checkbox type option, two simples and special price + * @return array + */ + private function getBundleConfiguration3() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple3', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required multi type option, two simples and special price + * @return array + */ + private function getBundleConfiguration4() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple5', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 4, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required option, one non required and special price + * @return array + */ + private function getBundleConfiguration5() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => false, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple3', + 'qty' => 1, + ], + [ + 'sku' => 'simple4', + 'qty' => 3, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one simple product with special price + * @return array + */ + private function getBundleConfiguration6() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple2', + 'qty' => 4, + ], + [ + 'sku' => 'simple5', + 'qty' => 1, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithTierPriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithTierPriceCalculatorTest.php new file mode 100644 index 0000000000000..620fd72278435 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithTierPriceCalculatorTest.php @@ -0,0 +1,644 @@ +tierPriceFactory = $this->objectManager->create(ProductTierPriceInterfaceFactory::class); + } + + /** + * @param array $strategyModifiers + * @param array $expectedResults + * @dataProvider getTestCases + * @magentoAppIsolation enabled + */ + public function testPriceForDynamicBundle(array $strategyModifiers, array $expectedResults) + { + $this->prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * Test cases for current test + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getTestCases() + { + return [ + ' + #1 Testing product price for dynamic bundle + with one required option and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration1(), + 'expectedResults' => [ + // 0.5 * 10 + 'minimalPrice' => 5, + // 0.5 * 10 + 'maximalPrice' => 5 + ] + ], + + ' + #2 Testing product price for dynamic bundle + with one non required option and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration2(), + 'expectedResults' => [ + // 0.5 * 2 * 10 + 'minimalPrice' => 10, + // 0.5 * 2 * 10 + 'maximalPrice' => 10 + ] + ], + + ' + #3 Testing product price for dynamic bundle + with one required checkbox type option and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration3(), + 'expectedResults' => [ + // 0.5 * 1 * 10 + 'minimalPrice' => 5, + // 0.5 * (1 * 10 + 3 * 20) + 'maximalPrice' => 35 + ] + ], + + ' + #4 Testing product price for dynamic bundle + with one required multi type option and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration4(), + 'expectedResults' => [ + // 0.5 * 1 * 10 + 'minimalPrice' => 5, + // 0.5 * (1 * 10 + 3 * 20) + 'maximalPrice' => 35 + ] + ], + + ' + #5 Testing product price for dynamic bundle + with one required radio type option and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration5(), + 'expectedResults' => [ + // 0.5 * 1 * 10 + 'minimalPrice' => 5, + // 0.5 * 3 * 20 + 'maximalPrice' => 30 + ] + ], + + ' + #6 Testing product price for dynamic bundle + with two required options and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration6(), + 'expectedResults' => [ + // 0.5 * (1 * 10 + 1 * 10) + 'minimalPrice' => 10, + // 0.5 * (3 * 20 + 1 * 10 + 3 * 20) + 'maximalPrice' => 65 + ] + ], + + ' + #7 Testing product price for dynamic bundle + with one required option, one non required option and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration7(), + 'expectedResults' => [ + // 0.5 * (1 * 10) + 'minimalPrice' => 5, + // 0.5 * (3 * 20 + 1 * 10 + 3 * 20) + 'maximalPrice' => 65 + ] + ], + + ' + #8 Testing product price for dynamic bundle + with two non required options and tier price + ' => [ + 'strategy' => $this->getBundleConfiguration8(), + 'expectedResults' => [ + // 0.5 * (1 * 10) + 'minimalPrice' => 5, + // 0.5 * (3 * 20 + 1 * 10 + 3 * 20) + 'maximalPrice' => 65 + ] + ], + + ' + #9 Testing product price for dynamic bundle + with tier price and with simple with tier price + ' => [ + 'strategy' => $this->getBundleConfiguration9(), + 'expectedResults' => [ + // 0.5 * 1 * 2.5 + 'minimalPrice' => 1.25, + // 0.5 * 3 * 20 + 'maximalPrice' => 30 + ] + ], + ]; + } + + /** + * Dynamic bundle with one required option and tier price + * @return array + */ + private function getBundleConfiguration1() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one non required option and tier price + * @return array + */ + private function getBundleConfiguration2() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'type' => 'checkbox', + 'required' => false, + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 2, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required checkbox type option and tier price + * @return array + */ + private function getBundleConfiguration3() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required multi type option and tier price + * @return array + */ + private function getBundleConfiguration4() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'multi', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required radio type option and tier price + * @return array + */ + private function getBundleConfiguration5() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with two required options and tier price + * @return array + */ + private function getBundleConfiguration6() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with one required option, one non required option and tier price + * @return array + */ + private function getBundleConfiguration7() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => false, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with two non required options and tier price + * @return array + */ + private function getBundleConfiguration8() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => false, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => false, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Dynamic bundle with tier price and with simple with tier price + * @return array + */ + private function getBundleConfiguration9() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + ], + [ + 'sku' => 'simple2', + 'qty' => 3, + ], + ] + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + $tierPriceSimpleProductData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 2.5 + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addTierPriceForSimple', + 'data' => ['simple1', $tierPriceSimpleProductData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * @param \Magento\Catalog\Model\Product $product + * @param array $tirePriceData + * @return \Magento\Catalog\Model\Product + */ + protected function addTierPrice(\Magento\Catalog\Model\Product $product, $tirePriceData) + { + $tierPrice = $this->tierPriceFactory->create([ + 'data' => $tirePriceData + ]); + $product->setTierPrices([$tierPrice]); + + return $product; + } + + /** + * @param \Magento\Catalog\Model\Product $bundleProduct + * @param string $sku + * @param array $tirePriceData + * @return \Magento\Catalog\Model\Product + */ + protected function addTierPriceForSimple(\Magento\Catalog\Model\Product $bundleProduct, $sku, $tirePriceData) + { + $simple = $this->productRepository->get($sku, false, null, true); + $simple = $this->addTierPrice($simple, $tirePriceData); + $this->productRepository->save($simple); + + return $bundleProduct; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundlePriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundlePriceCalculatorTest.php new file mode 100644 index 0000000000000..ed394fc523fc1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundlePriceCalculatorTest.php @@ -0,0 +1,394 @@ +prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * @param array $strategyModifiers + * @param array $expectedResults + * @dataProvider getTestCases + * @magentoAppIsolation enabled + * @magentoConfigFixture current_store catalog/price/scope 1 + */ + public function testPriceForFixedBundleInWebsiteScope(array $strategyModifiers, array $expectedResults) + { + $this->prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * Test cases for current test + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getTestCases() + { + return [ + '#1 Testing price for fixed bundle product with one simple' => [ + 'strategy' => $this->getProductWithOneSimple(), + 'expectedResults' => [ + // 110 + 10 (price from simple1) + 'minimalPrice' => 120, + // 110 + 10 (sum of simple price) + 'maximalPrice' => 120 + ] + ], + + '#2 Testing price for fixed bundle product with three simples and different qty' => [ + 'strategy' => $this->getProductWithDifferentQty(), + 'expectedResults' => [ + // 110 + 10 (min price from simples) + 'minimalPrice' => 120, + // 110 + (3 * 10) + (2 * 10) + 10 + 'maximalPrice' => 170 + ] + ], + + '#3 Testing price for fixed bundle product with three simples and different price' => [ + 'strategy' => $this->getProductWithDifferentPrice(), + 'expectedResults' => [ + // 110 + 10 + 'minimalPrice' => 120, + // 110 + 60 + 'maximalPrice' => 170 + ] + ], + + '#4 Testing price for fixed bundle product with three simples' => [ + 'strategy' => $this->getProductWithSamePrice(), + 'expectedResults' => [ + // 110 + 10 + 'minimalPrice' => 120, + // 110 + 30 + 'maximalPrice' => 140 + ] + ], + + ' + #5 Testing price for fixed bundle product + with fixed sub items, fixed options and without any discounts + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 110 + 1 * 20 + 100 + 'minimalPrice' => 230, + + // 110 + 1 * 20 + 100 + 'maximalPrice' => 230 + ] + ], + + ' + #6 Testing price for fixed bundle product + with percent sub items, percent options and without any discounts + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 110 + 110 * 0.2 + 110 * 1 + 'minimalPrice' => 242, + + // 110 + 110 * 0.2 + 110 * 1 + 'maximalPrice' => 242 + ] + ], + + ' + #7 Testing price for fixed bundle product + with fixed sub items, percent options and without any discounts + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 110 + 1 * 20 + 110 * 1 + 'minimalPrice' => 240, + + // 110 + 1 * 20 + 110 * 1 + 'maximalPrice' => 240 + ] + ], + + ' + #8 Testing price for fixed bundle product + with percent sub items, fixed options and without any discounts + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 110 + 110 * 0.2 + 100 + 'minimalPrice' => 232, + + // 110 + 110 * 0.2 + 100 + 'maximalPrice' => 232 + ] + ], + ]; + } + + /** + * Fixed bundle product with one simple + * @return array + */ + private function getProductWithOneSimple() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'price' => 10, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + ] + ], + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Fixed bundle product with three simples and different qty + * @return array + */ + private function getProductWithDifferentQty() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'price' => 10, + 'qty' => 3, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 2, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + [ + 'sku' => 'simple3', + 'price' => 10, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Fixed bundle product with three simples and different price + * @return array + */ + private function getProductWithSamePrice() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'price' => 10, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + [ + 'sku' => 'simple3', + 'price' => 10, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ] + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Fixed bundle product with three simples + * @return array + */ + private function getProductWithDifferentPrice() + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'price' => 10, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + [ + 'sku' => 'simple2', + 'price' => 20, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ], + [ + 'sku' => 'simple3', + 'price' => 30, + 'qty' => 1, + 'price_type' => LinkInterface::PRICE_TYPE_FIXED, + ] + ] + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + ]; + } + + /** + * Fixed bundle product with required option, custom option and without any discounts + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration3($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 20, + 'price_type' => $selectionsPriceType + ], + ] + ], + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithCatalogPriceRuleCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithCatalogPriceRuleCalculatorTest.php new file mode 100644 index 0000000000000..ea086d59ceaa6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithCatalogPriceRuleCalculatorTest.php @@ -0,0 +1,810 @@ +prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * Test cases for current test + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getTestCases() + { + return [ + ' + #1 Testing price for fixed bundle product + with catalog price rule and without sub items and options + ' => [ + 'strategy' => $this->getBundleConfiguration1(), + 'expectedResults' => [ + // 110 * 0.9 + 'minimalPrice' => 99, + + // 110 * 0.9 + 'maximalPrice' => 99 + ] + ], + + ' + #2 Testing price for fixed bundle product + with catalog price rule, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 20 + 100 + 'minimalPrice' => 219, + + // 0.9 * 110 + 1 * 20 + 100 + 'maximalPrice' => 219 + ] + ], + + ' + #3 Testing price for fixed bundle product + with catalog price rule, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 0.9 * 110 * 0.2 + 0.9 * 110 * 1 + 'minimalPrice' => 217.8, + + // 0.9 * 110 + 0.9 * 110 * 0.2 + 0.9 * 110 * 1 + 'maximalPrice' => 217.8 + ] + ], + + ' + #4 Testing price for fixed bundle product + with catalog price rule, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 20 + 0.9 * 110 * 1 + 'minimalPrice' => 218, + + // 0.9 * 110 + 1 * 20 + 0.9 * 110 * 1 + 'maximalPrice' => 218 + ] + ], + + ' + #5 Testing price for fixed bundle product + with catalog price rule, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 0.9 * 110 * 0.2 + 100 + 'minimalPrice' => 218.8, + + // 0.9 * 110 + 0.9 * 110 * 0.2 + 100 + 'maximalPrice' => 218.8 + ] + ], + + ' + #6 Testing price for fixed bundle product + with catalog price rule, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 100 + 'minimalPrice' => 199, + + // 0.9 * 110 + 2 * 20 + 100 + 'maximalPrice' => 239 + ] + ], + + ' + #7 Testing price for fixed bundle product + with catalog price rule, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 0.9 * 110 * 1 + 'minimalPrice' => 198, + + // 0.9 * 110 + 2 * 0.9 * 110 * 0.2 + 1 * 0.9 * 110 + 'maximalPrice' => 237.6 + ] + ], + + ' + #8 Testing price for fixed bundle product + with catalog price rule, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 0.9 * 110 + 'minimalPrice' => 198, + + // 0.9 * 110 + 2 * 20 + 1 * 0.9 * 110 + 'maximalPrice' => 238 + ] + ], + + ' + #9 Testing price for fixed bundle product + with catalog price rule, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 100 + 'minimalPrice' => 199, + + // 0.9 * 110 + 2 * 0.2 * 0.9 * 110 + 100 + 'maximalPrice' => 238.6 + ] + ], + + ' + #10 Testing price for fixed bundle product + with catalog price rule, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 3 * 10 + 100 + 'minimalPrice' => 229, + + // 0.9 * 110 + 3 * 10 + 1 * 40 + 100 + 'maximalPrice' => 269 + ] + ], + + ' + #11 Testing price for fixed bundle product + with catalog price rule, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 3 * 0.9 * 110 * 0.1 + 0.9 * 110 * 1 + 'minimalPrice' => 227.7, + + // 0.9 * 110 + 3 * 0.9 * 110 * 0.1 + 1 * 0.9 * 110 * 0.4 + 0.9 * 110 * 1 + 'maximalPrice' => 267.3 + ] + ], + + ' + #12 Testing price for fixed bundle product + with catalog price rule, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 3 * 10 + 1 * 0.9 * 110 + 'minimalPrice' => 228, + + // 0.9 * 110 + 3 * 10 + 1 * 40 + 1 * 0.9 * 110 + 'maximalPrice' => 268 + ] + ], + + ' + #13 Testing price for fixed bundle product + with catalog price rule, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 3 * 0.9 * 110 * 0.1 + 100 + 'minimalPrice' => 228.7, + + // 0.9 * 110 + 3 * 0.9 * 110 * 0.1 + 1 * 0.9 * 110 * 0.4 + 100 + 'maximalPrice' => 268.3 + ] + ], + + ' + #14 Testing price for fixed bundle product + with catalog price rule, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 40 + 100 + 'minimalPrice' => 239, + + // 0.9 * 110 + 1 * 40 + 3 * 15 + 100 + 'maximalPrice' => 284 + ] + ], + + ' + #15 Testing price for fixed bundle product + with catalog price rule, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 1 * 0.9 * 110 + 'minimalPrice' => 237.6, + + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 3 * 0.9 * 110 * 0.15 + 0.9 * 110 * 1 + 'maximalPrice' => 282.15 + ] + ], + + ' + #16 Testing price for fixed bundle product + with catalog price rule, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 40 + 1 * 0.9 * 110 + 'minimalPrice' => 238, + + // 0.9 * 110 + 1 * 40 + 3 * 15 + 1 * 0.9 * 110 + 'maximalPrice' => 283 + ] + ], + + ' + #17 Testing price for fixed bundle product + with catalog price rule, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 100 + 'minimalPrice' => 238.6, + + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 3 * 0.9 * 110 * 0.15 + 100 + 'maximalPrice' => 283.15 + ] + ], + + ' + #18 Testing price for fixed bundle product + with catalog price rule, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 40 + 100 + 'minimalPrice' => 239, + + // 0.9 * 110 + 3 * 15 + 100 + 'maximalPrice' => 244 + ] + ], + + ' + #19 Testing price for fixed bundle product + with catalog price rule, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 1 * 0.9 * 110 + 'minimalPrice' => 237.6, + + // 0.9 * 110 + 3 * 0.9 * 110 * 0.15 + 1 * 0.9 * 110 + 'maximalPrice' => 242.55 + ] + ], + + ' + #20 Testing price for fixed bundle product + with catalog price rule, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 40 + 0.9 * 110 * 1 + 'minimalPrice' => 238, + + // 0.9 * 110 + 3 * 15 + 0.9 * 110 * 1 + 'maximalPrice' => 243 + ] + ], + + ' + #21 Testing price for fixed bundle product + with catalog price rule, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 100 + 'minimalPrice' => 238.6, + + // 0.9 * 110 + 3 * 0.9 * 110 * 0.15 + 100 + 'maximalPrice' => 243.55 + ] + ], + + ' + #22 Testing price for fixed bundle product + with catalog price rule, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 40 + 1 * 20 + 100 + 'minimalPrice' => 259, + + // 0.9 * 110 + 3 * 15 + 1 * 20 + 3 * 10 + 100 + 'maximalPrice' => 294 + ] + ], + + ' + #23 Testing price for fixed bundle product + with catalog price rule, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 1 * 0.9 * 110 * 0.2 + 0.9 * 110 * 1 + 'minimalPrice' => 257.4, + + // 0.9 * 110 + 3 * 0.9 * 110 * 0.15 + 1 * 0.9 * 110 * 0.2 + 3 * 0.9 * 110 * 0.1 + 0.9 * 110 * 1 + 'maximalPrice' => 292.05 + ] + ], + + ' + #24 Testing price for fixed bundle product + with catalog price rule, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 40 + 1 * 20 + 1 * 0.9 * 110 + 'minimalPrice' => 258, + + // 0.9 * 110 + 3 * 15 + 1 * 20 + 3 * 10 + 1 * 0.9 * 110 + 'maximalPrice' => 293 + ] + ], + + ' + #25 Testing price for fixed bundle product + with catalog price rule, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.9 * 110 + 1 * 0.9 * 110 * 0.4 + 1 * 0.9 * 110 * 0.2 + 100 + 'minimalPrice' => 258.4, + + // 0.9 * 110 + 3 * 0.9 * 110 * 0.15 + 1 * 0.9 * 110 * 0.2 + 3 * 0.9 * 110 * 0.1 + 100 + 'maximalPrice' => 293.05 + ] + ], + ]; + } + + /** + * Fixed bundle product with catalog price rule and without sub items and options + * @return array + */ + private function getBundleConfiguration1() + { + return []; + } + + /** + * Fixed bundle product with catalog price rule, one required option and one custom option + * @param string $selectionsPriceType + * @param string $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration2($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 20, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with catalog price rule, one non required option and one custom option + * @param string $selectionsPriceType + * @param string $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration3($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'type' => 'checkbox', + 'required' => false, + 'links' => [ + [ + 'sku' => 'simple1', + 'price' => 20, + 'qty' => 2, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with catalog price rule, one checkbox type option with 2 simples and one custom option + * @param string $selectionsPriceType + * @param string $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration4($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with catalog price rule, one multi type option with 2 simples and one custom option + * @param string $selectionsPriceType + * @param string $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration5($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'multi', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with catalog price rule, one radio type option with 2 simples and one custom option + * @param string $selectionsPriceType + * @param string $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration6($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with catalog price rule, two required options and one custom option + * @param string $selectionsPriceType + * @param string $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration7($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 20, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithSpecialPriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithSpecialPriceCalculatorTest.php new file mode 100644 index 0000000000000..9fc01c1354347 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithSpecialPriceCalculatorTest.php @@ -0,0 +1,822 @@ +prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * Test cases for current test + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getTestCases() + { + return [ + ' + #1 Testing price for fixed bundle product + with special price and without any sub items and options + ' => [ + 'strategy' => $this->getBundleConfiguration1(), + 'expectedResults' => [ + // 110 * 0.5 + 'minimalPrice' => 55, + + // 110 * 0.5 + 'maximalPrice' => 55 + ] + ], + + ' + #2 Testing price for fixed bundle product + with special price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 20) + 100 + 'minimalPrice' => 165, + + // 0.5 * (110 + 1 * 20) + 100 + 'maximalPrice' => 165 + ] + ], + + ' + #3 Testing price for fixed bundle product + with special price, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 110 * 0.2 + 110 * 1) + 'minimalPrice' => 121, + + // 0.5 * (110 + 110 * 0.2 + 110 * 1) + 'maximalPrice' => 121 + ] + ], + + ' + #4 Testing price for fixed bundle product + with special price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 20 + 110 * 1) + 'minimalPrice' => 120, + + // 0.5 * (110 + 1 * 20 + 110 * 1) + 'maximalPrice' => 120 + ] + ], + + ' + #5 Testing price for fixed bundle product + with special price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration2( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 110 * 0.2) + 100 + 'minimalPrice' => 166, + + // 0.5 * (110 + 110 * 0.2) + 100 + 'maximalPrice' => 166 + ] + ], + + ' + #6 Testing price for fixed bundle product + with special price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * 110 + 100 + 'minimalPrice' => 155, + + // 0.5 * (110 + 2 * 20) + 100 + 'maximalPrice' => 175 + ] + ], + + ' + #7 Testing price for fixed bundle product + with special price, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 110 * 1) + 'minimalPrice' => 110, + + // 0.5 * (110 + 2 * 110 * 0.2 + 1 * 110) + 'maximalPrice' => 132 + ] + ], + + ' + #8 Testing price for fixed bundle product + with special price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110) + 'minimalPrice' => 110, + + // 0.5 * (110 + 2 * 20 + 1 * 110) + 'maximalPrice' => 130 + ] + ], + + ' + #9 Testing price for fixed bundle product + with special price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * 110 + 100 + 'minimalPrice' => 155, + + // 0.5 * (110 + 2 * 0.2 * 110) + 100 + 'maximalPrice' => 177 + ] + ], + + ' + #10 Testing price for fixed bundle product + with special price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 10) + 100 + 'minimalPrice' => 170, + + // 0.5 * (110 + 3 * 10 + 1 * 40) + 100 + 'maximalPrice' => 190 + ] + ], + + ' + #11 Testing price for fixed bundle product + with special price, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 110 * 0.1 + 110 * 1) + 'minimalPrice' => 126.5, + + // 0.5 * (110 + 3 * 110 * 0.1 + 1 * 110 * 0.4 + 110 * 1) + 'maximalPrice' => 148.5 + ] + ], + + ' + #12 Testing price for fixed bundle product + with special price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 10 + 1 * 110) + 'minimalPrice' => 125, + + // 0.5 * (110 + 3 * 10 + 1 * 40 + 1 * 110) + 'maximalPrice' => 145 + ] + ], + + ' + #13 Testing price for fixed bundle product + with special price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration4( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 110 * 0.1) + 100 + 'minimalPrice' => 171.5, + + // 0.5 * (110 + 3 * 110 * 0.1 + 1 * 110 * 0.4) + 100 + 'maximalPrice' => 193.5 + ] + ], + + ' + #14 Testing price for fixed bundle product + with special price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40) + 100 + 'minimalPrice' => 175, + + // 0.5 * (110 + 1 * 40 + 3 * 15) + 100 + 'maximalPrice' => 197.5 + ] + ], + + ' + #15 Testing price for fixed bundle product + with special price, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110) + 'minimalPrice' => 132, + + // 0.5 * (110 + 1 * 110 * 0.4 + 3 * 110 * 0.15 + 110 * 1) + 'maximalPrice' => 156.75 + ] + ], + + ' + #16 Testing price for fixed bundle product + with special price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 1 * 110) + 'minimalPrice' => 130, + + // 0.5 * (110 + 1 * 40 + 3 * 15 + 1 * 110) + 'maximalPrice' => 152.5 + ] + ], + + ' + #17 Testing price for fixed bundle product + with special price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration5( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4) + 100 + 'minimalPrice' => 177, + + // 0.5 * (110 + 1 * 110 * 0.4 + 3 * 110 * 0.15) + 100 + 'maximalPrice' => 201.75 + ] + ], + + ' + #18 Testing price for fixed bundle product + with special price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40) + 100 + 'minimalPrice' => 175, + + // 0.5 * (110 + 3 * 15) + 100 + 'maximalPrice' => 177.5 + ] + ], + + ' + #19 Testing price for fixed bundle product + with special price, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110) + 'minimalPrice' => 132, + + // 0.5 * (110 + 3 * 110 * 0.15 + 1 * 110) + 'maximalPrice' => 134.75 + ] + ], + + ' + #20 Testing price for fixed bundle product + with special price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 110 * 1) + 'minimalPrice' => 130, + + // 0.5 * (110 + 3 * 15 + 110 * 1) + 'maximalPrice' => 132.5 + ] + ], + + ' + #21 Testing price for fixed bundle product + with special price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration6( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4) + 100 + 'minimalPrice' => 177, + + // 0.5 * (110 + 3 * 110 * 0.15) + 100 + 'maximalPrice' => 179.75 + ] + ], + + ' + #22 Testing price for fixed bundle product + with special price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 1 * 20) + 100 + 'minimalPrice' => 185, + + // 0.5 * (110 + 3 * 15 + 1 * 20 + 3 * 10) + 100 + 'maximalPrice' => 202.5 + ] + ], + + ' + #23 Testing price for fixed bundle product + with special price, percent sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110 * 0.2 + 110 * 1) + 'minimalPrice' => 143, + + // 0.5 * (110 + 3 * 110 * 0.15 + 1 * 110 * 0.2 + 3 * 110 * 0.1 + 110 * 1) + 'maximalPrice' => 162.25 + ] + ], + + ' + #24 Testing price for fixed bundle product + with special price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 1 * 20 + 1 * 110) + 'minimalPrice' => 140, + + // 0.5 * (110 + 3 * 15 + 1 * 20 + 3 * 10 + 1 * 110) + 'maximalPrice' => 157.5 + ] + ], + + ' + #25 Testing price for fixed bundle product + with special price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getBundleConfiguration7( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110 * 0.2) + 100 + 'minimalPrice' => 188, + + // 0.5 * (110 + 3 * 110 * 0.15 + 1 * 110 * 0.2 + 3 * 110 * 0.1) + 100 + 'maximalPrice' => 207.25 + ] + ], + ]; + } + + /** + * Fixed bundle product with special price and without any sub items and options + * @return array + */ + private function getBundleConfiguration1() + { + return []; + } + + /** + * Fixed bundle product with required option, custom option and with special price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration2( + $selectionsPriceType, + $customOptionsPriceType + ) { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 20, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with non required option, custom option and with special price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration3( + $selectionsPriceType, + $customOptionsPriceType + ) { + $optionsData = [ + [ + 'title' => 'Op1', + 'type' => 'checkbox', + 'required' => false, + 'links' => [ + [ + 'sku' => 'simple1', + 'price' => 20, + 'qty' => 2, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with checkbox type option, custom option and with special price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration4( + $selectionsPriceType, + $customOptionsPriceType + ) { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with multi type option, custom option and with special price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration5( + $selectionsPriceType, + $customOptionsPriceType + ) { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'multi', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with radio type option, custom option and with special price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration6( + $selectionsPriceType, + $customOptionsPriceType + ) { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with two required options, custom option and with special price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getBundleConfiguration7( + $selectionsPriceType, + $customOptionsPriceType + ) { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 20, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + return [ + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithTierPriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithTierPriceCalculatorTest.php new file mode 100644 index 0000000000000..1b217a7d080d3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithTierPriceCalculatorTest.php @@ -0,0 +1,915 @@ +tierPriceFactory = $this->objectManager->create(ProductTierPriceInterfaceFactory::class); + } + + /** + * @param array $strategyModifiers + * @param array $expectedResults + * @dataProvider getTestCases + * @magentoAppIsolation enabled + */ + public function testPriceForFixedBundle(array $strategyModifiers, array $expectedResults) + { + $this->prepareFixture($strategyModifiers, 'bundle_product'); + $bundleProduct = $this->productRepository->get('bundle_product', false, null, true); + + /** @var \Magento\Framework\Pricing\PriceInfo\Base $priceInfo */ + $priceInfo = $bundleProduct->getPriceInfo(); + $priceCode = \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE; + + $this->assertEquals( + $expectedResults['minimalPrice'], + $priceInfo->getPrice($priceCode)->getMinimalPrice()->getValue(), + 'Failed to check minimal price on product' + ); + + $this->assertEquals( + $expectedResults['maximalPrice'], + $priceInfo->getPrice($priceCode)->getMaximalPrice()->getValue(), + 'Failed to check maximal price on product' + ); + } + + /** + * Test cases for current test + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getTestCases() + { + return [ + ' + #1 Testing product price + with tier price and without any sub items and options + ' => [ + 'strategy' => $this->getBundleConfiguration1(), + 'expectedResults' => [ + // 110 * 0.5 + 'minimalPrice' => 55, + + // 110 * 0.5 + 'maximalPrice' => 55 + ] + ], + + ' + #2 Testing product price + with tier price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration2( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 20) + 100 + 'minimalPrice' => 165, + + // 0.5 * (110 + 1 * 20) + 100 + 'maximalPrice' => 165 + ] + ], + + ' + #3 Testing product price + with tier price, percent sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration2( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 110 * 0.2 + 110 * 1) + 'minimalPrice' => 121, + + // 0.5 * (110 + 110 * 0.2 + 110 * 1) + 'maximalPrice' => 121 + ] + ], + + ' + #4 Testing product price + with tier price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration2( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 20 + 110 * 1) + 'minimalPrice' => 120, + + // 0.5 * (110 + 1 * 20 + 110 * 1) + 'maximalPrice' => 120 + ] + ], + + ' + #5 Testing product price + with tier price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration2( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 110 * 0.2) + 100 + 'minimalPrice' => 166, + + // 0.5 * (110 + 110 * 0.2) + 100 + 'maximalPrice' => 166 + ] + ], + + ' + #6 Testing product price + with tier price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * 110 + 100 + 'minimalPrice' => 155, + + // 0.5 * (110 + 2 * 20) + 100 + 'maximalPrice' => 175 + ] + ], + + ' + #7 Testing product price + with tier price, percent sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 110 * 1) + 'minimalPrice' => 110, + + // 0.5 * (110 + 2 * 110 * 0.2 + 1 * 110) + 'maximalPrice' => 132 + ] + ], + + ' + #8 Testing product price + with tier price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration3( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110) + 'minimalPrice' => 110, + + // 0.5 * (110 + 2 * 20 + 1 * 110) + 'maximalPrice' => 130 + ] + ], + + ' + #9 Testing product price + with tier price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration3( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * 110 + 100 + 'minimalPrice' => 155, + + // 0.5 * (110 + 2 * 0.2 * 110) + 100 + 'maximalPrice' => 177 + ] + ], + + ' + #10 Testing product price + with tier price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration4( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 10) + 100 + 'minimalPrice' => 170, + + // 0.5 * (110 + 3 * 10 + 1 * 40) + 100 + 'maximalPrice' => 190 + ] + ], + + ' + #11 Testing product price + with tier price, percent sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration4( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 110 * 0.1 + 110 * 1) + 'minimalPrice' => 126.5, + + // 0.5 * (110 + 3 * 110 * 0.1 + 1 * 110 * 0.4 + 110 * 1) + 'maximalPrice' => 148.5 + ] + ], + + ' + #12 Testing product price + with tier price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration4( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 10 + 1 * 110) + 'minimalPrice' => 125, + + // 0.5 * (110 + 3 * 10 + 1 * 40 + 1 * 110) + 'maximalPrice' => 145 + ] + ], + + ' + #13 Testing product price + with tier price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration4( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 3 * 110 * 0.1) + 100 + 'minimalPrice' => 171.5, + + // 0.5 * (110 + 3 * 110 * 0.1 + 1 * 110 * 0.4) + 100 + 'maximalPrice' => 193.5 + ] + ], + + ' + #14 Testing product price + with tier price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration5( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40) + 100 + 'minimalPrice' => 175, + + // 0.5 * (110 + 1 * 40 + 3 * 15) + 100 + 'maximalPrice' => 197.5 + ] + ], + + ' + #15 Testing product price + with tier price, percent sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration5( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110) + 'minimalPrice' => 132, + + // 0.5 * (110 + 1 * 110 * 0.4 + 3 * 110 * 0.15 + 110 * 1) + 'maximalPrice' => 156.75 + ] + ], + + ' + #16 Testing product price + with tier price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration5( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 1 * 110) + 'minimalPrice' => 130, + + // 0.5 * (110 + 1 * 40 + 3 * 15 + 1 * 110) + 'maximalPrice' => 152.5 + ] + ], + + ' + #17 Testing product price + with tier price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration5( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4) + 100 + 'minimalPrice' => 177, + + // 0.5 * (110 + 1 * 110 * 0.4 + 3 * 110 * 0.15) + 100 + 'maximalPrice' => 201.75 + ] + ], + + ' + #18 Testing product price + with tier price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration6( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40) + 100 + 'minimalPrice' => 175, + + // 0.5 * (110 + 3 * 15) + 100 + 'maximalPrice' => 177.5 + ] + ], + + ' + #19 Testing product price + with tier price, percent sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration6( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110) + 'minimalPrice' => 132, + + // 0.5 * (110 + 3 * 110 * 0.15 + 1 * 110) + 'maximalPrice' => 134.75 + ] + ], + + ' + #20 Testing product price + with tier price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration6( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 110 * 1) + 'minimalPrice' => 130, + + // 0.5 * (110 + 3 * 15 + 110 * 1) + 'maximalPrice' => 132.5 + ] + ], + + ' + #21 Testing product price + with tier price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration6( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4) + 100 + 'minimalPrice' => 177, + + // 0.5 * (110 + 3 * 110 * 0.15) + 100 + 'maximalPrice' => 179.75 + ] + ], + + ' + #22 Testing product price + with tier price, fixed sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration7( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 1 * 20) + 100 + 'minimalPrice' => 185, + + // 0.5 * (110 + 3 * 15 + 1 * 20 + 3 * 10) + 100 + 'maximalPrice' => 202.5 + ] + ], + + ' + #23 Testing product price + with tier price, percent sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration7( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110 * 0.2 + 110 * 1) + 'minimalPrice' => 143, + + // 0.5 * (110 + 3 * 110 * 0.15 + 1 * 110 * 0.2 + 3 * 110 * 0.1 + 110 * 1) + 'maximalPrice' => 162.25 + ] + ], + + ' + #24 Testing product price + with tier price, fixed sub items and percent options + ' => [ + 'strategy' => $this->getProductConfiguration7( + LinkInterface::PRICE_TYPE_FIXED, + self::CUSTOM_OPTION_PRICE_TYPE_PERCENT + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 40 + 1 * 20 + 1 * 110) + 'minimalPrice' => 140, + + // 0.5 * (110 + 3 * 15 + 1 * 20 + 3 * 10 + 1 * 110) + 'maximalPrice' => 157.5 + ] + ], + + ' + #25 Testing product price + with tier price, percent sub items and fixed options + ' => [ + 'strategy' => $this->getProductConfiguration7( + LinkInterface::PRICE_TYPE_PERCENT, + self::CUSTOM_OPTION_PRICE_TYPE_FIXED + ), + 'expectedResults' => [ + // 0.5 * (110 + 1 * 110 * 0.4 + 1 * 110 * 0.2) + 100 + 'minimalPrice' => 188, + + // 0.5 * (110 + 3 * 110 * 0.15 + 1 * 110 * 0.2 + 3 * 110 * 0.1) + 100 + 'maximalPrice' => 207.25 + ] + ], + ]; + } + + /** + * Fixed bundle product without sub items and options and with tier price + * @return array + */ + private function getBundleConfiguration1() + { + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ] + ]; + } + + /** + * Fixed bundle product with required option, custom option and with tier price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getProductConfiguration2($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 20, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with non required option, custom option and with tier price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getProductConfiguration3($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'type' => 'checkbox', + 'required' => false, + 'links' => [ + [ + 'sku' => 'simple1', + 'price' => 20, + 'qty' => 2, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with checkbox type option, custom option and with tier price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getProductConfiguration4($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with multi type option, custom option and with tier price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getProductConfiguration5($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'multi', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with radio type option, custom option and with tier price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getProductConfiguration6($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * Fixed bundle product with two required options, custom option and with tier price + * @param $selectionsPriceType + * @param $customOptionsPriceType + * @return array + */ + private function getProductConfiguration7($selectionsPriceType, $customOptionsPriceType) + { + $optionsData = [ + [ + 'title' => 'Op1', + 'required' => true, + 'type' => 'radio', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 40, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 15, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ], + [ + 'title' => 'Op2', + 'required' => true, + 'type' => 'checkbox', + 'links' => [ + [ + 'sku' => 'simple1', + 'qty' => 1, + 'price' => 20, + 'price_type' => $selectionsPriceType + ], + [ + 'sku' => 'simple2', + 'price' => 10, + 'qty' => 3, + 'price_type' => $selectionsPriceType + ], + ] + ] + ]; + + $customOptionsData = [ + [ + 'price_type' => $customOptionsPriceType, + 'title' => 'Test Field', + 'type' => 'field', + 'is_require' => 1, + 'price' => 100, + 'sku' => '1-text', + ] + ]; + + $tierPriceData = [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 1, + 'value' => 50, + 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) + ]; + + return [ + [ + 'modifierName' => 'addTierPrice', + 'data' => [$tierPriceData] + ], + [ + 'modifierName' => 'addSimpleProduct', + 'data' => [$optionsData] + ], + [ + 'modifierName' => 'addCustomOption', + 'data' => [$customOptionsData] + ], + ]; + } + + /** + * @param \Magento\Catalog\Model\Product $product + * @param array $tirePriceData + * @return \Magento\Catalog\Model\Product + */ + protected function addTierPrice(\Magento\Catalog\Model\Product $product, $tirePriceData) + { + $tierPrice = $this->tierPriceFactory->create([ + 'data' => $tirePriceData + ]); + $product->setTierPrices([$tierPrice]); + + return $product; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/IsSaleableTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/IsSaleableTest.php new file mode 100644 index 0000000000000..8640a6bad51d3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/IsSaleableTest.php @@ -0,0 +1,392 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + } + + /** + * Check bundle product is saleable if his status is enabled + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnEnabledStatus() + { + $bundleProduct = $this->productRepository->get('bundle-product'); + $bundleProduct->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED); + + $this->assertTrue( + $bundleProduct->isSalable(), + 'Bundle product supposed to be saleable + if his status is enabled' + ); + } + + /** + * Check bundle product is NOT saleable if his status is disabled + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnDisabledStatus() + { + $bundleProduct = $this->productRepository->get('bundle-product'); + $bundleProduct->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if his status is disabled' + ); + } + + /** + * Check bundle product is saleable if his status is enabled + * and it has internal data is_salable = true + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnEnabledStatusAndIsSalableIsTrue() + { + $bundleProduct = $this->productRepository->get('bundle-product'); + $bundleProduct->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED); + $bundleProduct->setData('is_salable', true); + + $this->assertTrue( + $bundleProduct->isSalable(), + 'Bundle product supposed to be saleable + if his status is enabled and it has data is_salable = true' + ); + } + + /** + * Check bundle product is NOT saleable if + * his status is enabled but his data is_salable = false + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnEnabledStatusAndIsSalableIsFalse() + { + $bundleProduct = $this->productRepository->get('bundle-product'); + $bundleProduct->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED); + $bundleProduct->setData('is_salable', false); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if his status is enabled but his data is_salable = false' + ); + } + + /** + * Check bundle product is saleable if it has all_items_salable = true + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnAllItemsSalableIsTrue() + { + $bundleProduct = $this->productRepository->get('bundle-product'); + $bundleProduct->setData('all_items_salable', true); + + $this->assertTrue( + $bundleProduct->isSalable(), + 'Bundle product supposed to be saleable + if it has data all_items_salable = true' + ); + } + + /** + * Check bundle product is NOT saleable if it has all_items_salable = false + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnAllItemsSalableIsFalse() + { + $bundleProduct = $this->productRepository->get('bundle-product'); + $bundleProduct->setData('all_items_salable', false); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if it has data all_items_salable = false' + ); + } + + /** + * Check bundle product is NOT saleable if it has no options + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithoutOptions() + { + $optionRepository = $this->objectManager->create(\Magento\Bundle\Api\ProductOptionRepositoryInterface::class); + $bundleProduct = $this->productRepository->get('bundle-product'); + + // TODO: make cleaner option deletion after fix MAGETWO-59465 + $ea = $bundleProduct->getExtensionAttributes(); + foreach ($ea->getBundleProductOptions() as $option) { + $optionRepository->delete($option); + } + $ea->setBundleProductOptions([]); + $bundleProduct->setExtensionAttributes($ea); + + $bundleProduct = $this->productRepository->save($bundleProduct); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if it has no options' + ); + } + + /** + * Check bundle product is NOT saleable if it has no selections + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithoutSelections() + { + $bundleProduct = $this->productRepository->get('bundle-product', true, null, true); + $bundleType = $bundleProduct->getTypeInstance(); + /** @var \Magento\Bundle\Model\LinkManagement $linkManager */ + $linkManager = $this->objectManager->create(\Magento\Bundle\Model\LinkManagement::class); + + /** @var \Magento\Bundle\Model\Product\Type $bundleType */ + $options = $bundleType->getOptionsCollection($bundleProduct); + $selections = $bundleType->getSelectionsCollection($options->getAllIds(), $bundleProduct); + + foreach ($selections as $link) { + /** @var \Magento\Bundle\Model\Selection $link */ + $linkManager->removeChild('bundle-product', $link->getOptionId(), $link->getSku()); + } + + $bundleProduct = $this->productRepository->get('bundle-product', false, null, true); + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if it has no selections' + ); + } + + /** + * Check bundle product is NOT saleable if + * all his selections are not saleable + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithoutSaleableSelections() + { + $productsSku = ['simple1', 'simple2', 'simple3', 'simple4', 'simple5']; + foreach ($productsSku as $productSku) { + $product = $this->productRepository->get($productSku); + $product->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); + $this->productRepository->save($product); + } + + $bundleProduct = $this->productRepository->get('bundle-product'); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if all his selections are not saleable' + ); + } + + /** + * Check bundle product is NOT saleable if + * it has at least one required option without saleable selections + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithoutSaleableSelectionsOnRequiredOption() + { + $productsSku = ['simple1', 'simple2', 'simple3']; + foreach ($productsSku as $productSku) { + $product = $this->productRepository->get($productSku); + $product->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); + $this->productRepository->save($product); + } + + $bundleProduct = $this->productRepository->get('bundle-product'); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if it has at least one required option with no saleable selections' + ); + } + + /** + * Check bundle product is NOT saleable if + * there are not enough qty of selection on required option + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithNotEnoughQtyOfSelection() + { + $this->setQtyForSelections(['simple1', 'simple2', 'simple3'], 1); + + $bundleProduct = $this->productRepository->get('bundle-product'); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be non saleable + if there are not enough qty of selections on required options' + ); + } + + /** + * Check bundle product is saleable if + * all his selections have selection_can_change_qty = 1 + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithSelectionCanChangeQty() + { + $this->setQtyForSelections(['simple1', 'simple2', 'simple3', 'simple4', 'simple5'], 1); + $bundleProduct = $this->productRepository->get('bundle-product'); + $options = $bundleProduct->getExtensionAttributes()->getBundleProductOptions(); + + foreach ($options as $productOption) { + $links = $productOption->getProductLinks(); + foreach ($links as $link) { + $link->setSelectionCanChangeQuantity(1); + } + + $productOption->setProductLinks($links); + } + + $extension = $bundleProduct->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $bundleProduct->setExtensionAttributes($extension); + + $bundleProduct = $this->productRepository->save($bundleProduct); + + $this->assertTrue( + $bundleProduct->isSalable(), + 'Bundle product supposed to be saleable + if all his selections have selection_can_change_qty = 1' + ); + } + + /** + * Check bundle product is not saleable if + * all his options are not required and selections are not saleable + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithoutRequiredOptions() + { + // making selections as not saleable + $productsSku = ['simple1', 'simple2', 'simple3', 'simple4', 'simple5']; + foreach ($productsSku as $productSku) { + $product = $this->productRepository->get($productSku); + $product->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); + $this->productRepository->save($product); + } + + $bundleProduct = $this->productRepository->get('bundle-product'); + + // setting all options as not required + $options = $bundleProduct->getExtensionAttributes()->getBundleProductOptions(); + foreach ($options as $productOption) { + $productOption->setRequired(false); + } + + $extension = $bundleProduct->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $bundleProduct->setExtensionAttributes($extension); + $bundleProduct = $this->productRepository->save($bundleProduct); + + $this->assertFalse( + $bundleProduct->isSalable(), + 'Bundle product supposed to be not saleable + if all his options are not required and selections are not saleable' + ); + } + + /** + * Check bundle product is saleable if + * it has at least one not required option with saleable selections + * + * @magentoAppIsolation enabled + * @covers \Magento\Bundle\Model\Product\Type::isSalable + */ + public function testIsSaleableOnBundleWithOneSaleableSelection() + { + // making selections as not saleable except simple3 + $productsSku = ['simple1', 'simple2', 'simple4', 'simple5']; + + foreach ($productsSku as $productSku) { + $product = $this->productRepository->get($productSku); + $product->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); + $this->productRepository->save($product); + } + + $bundleProduct = $this->productRepository->get('bundle-product'); + + // setting all options as not required + $options = $bundleProduct->getExtensionAttributes()->getBundleProductOptions(); + foreach ($options as $productOption) { + $productOption->setRequired(false); + } + + $extension = $bundleProduct->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $bundleProduct->setExtensionAttributes($extension); + + $bundleProduct = $this->productRepository->save($bundleProduct); + + $this->assertTrue( + $bundleProduct->isSalable(), + 'Bundle product supposed to be saleable + if it has at least one not required option with saleable selection' + ); + } + + private function setQtyForSelections($productsSku, $qty) + { + foreach ($productsSku as $productSku) { + $product = $this->productRepository->get($productSku); + $ea = $product->getExtensionAttributes(); + $ea->getStockItem()->setQty($qty); + $this->productRepository->save($product); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/OptionListTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/OptionListTest.php index b9c9fd4406150..cf6448dd9d4b4 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/OptionListTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/OptionListTest.php @@ -1,6 +1,6 @@ create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) + ->setId(42) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Bundle Product') + ->setSku('bundle_product') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setPriceView(0) + ->setPriceType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC) + ->setShipmentType(0); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_rollback.php new file mode 100644 index 0000000000000..cab3578ac69b5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_rollback.php @@ -0,0 +1,25 @@ +get(\Magento\Framework\Registry::class); +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('bundle_product', false, null, true); + $productRepository->delete($product); +} catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_with_catalog_rule.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_with_catalog_rule.php new file mode 100644 index 0000000000000..8974b632dc76d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_with_catalog_rule.php @@ -0,0 +1,8 @@ +create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$productRepository + ->get('bundle_product') + ->setSpecialPrice(50) + ->save(); + +$productRepository + ->get('simple2') + ->setSpecialPrice(2.5) + ->save(); + +$productRepository + ->get('simple5') + ->setSpecialPrice(9.9) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_with_special_price_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_with_special_price_rollback.php new file mode 100644 index 0000000000000..e6e0f174a263c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/dynamic_bundle_product_with_special_price_rollback.php @@ -0,0 +1,7 @@ +create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) + ->setId(42) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Bundle Product') + ->setSku('bundle_product') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setPriceView(0) + ->setPriceType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED) + ->setPrice(110.0) + ->setShipmentType(0); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_rollback.php new file mode 100644 index 0000000000000..cab3578ac69b5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_rollback.php @@ -0,0 +1,25 @@ +get(\Magento\Framework\Registry::class); +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $product = $productRepository->get('bundle_product', false, null, true); + $productRepository->delete($product); +} catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_with_catalog_rule.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_with_catalog_rule.php new file mode 100644 index 0000000000000..781726df28229 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_with_catalog_rule.php @@ -0,0 +1,8 @@ +create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$productRepository + ->get('bundle_product') + ->setSpecialPrice(50) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_with_special_price_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_with_special_price_rollback.php new file mode 100644 index 0000000000000..2282fe71acab3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/PriceCalculator/fixed_bundle_product_with_special_price_rollback.php @@ -0,0 +1,7 @@ +create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE) + ->setId(3) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Bundle Product') + ->setSku('bundle-product') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setPriceView(1) + ->setPriceType(1) + ->setPrice(10.0) + ->setShipmentType(0) + ->setBundleOptionsData( + [ + // Required "Drop-down" option + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'select', + 'required' => 1, + 'delete' => '', + ], + // Required "Radio Buttons" option + [ + 'title' => 'Option 2', + 'default_title' => 'Option 2', + 'type' => 'radio', + 'required' => 1, + 'delete' => '', + ], + // Required "Checkbox" option + [ + 'title' => 'Option 3', + 'default_title' => 'Option 3', + 'type' => 'checkbox', + 'required' => 1, + 'delete' => '', + ], + // Required "Multiple Select" option + [ + 'title' => 'Option 4', + 'default_title' => 'Option 4', + 'type' => 'multi', + 'required' => 1, + 'delete' => '', + ], + // Non-required "Multiple Select" option + [ + 'title' => 'Option 5', + 'default_title' => 'Option 5', + 'type' => 'multi', + 'required' => 0, + 'delete' => '', + ] + ] + )->setBundleSelectionsData( + [ + [ + [ + 'product_id' => 10, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 1 + ], + [ + 'product_id' => 11, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 1 + ], + [ + 'product_id' => 12, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 1 + ] + ], + [ + [ + 'product_id' => 10, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 2 + ], + [ + 'product_id' => 11, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 2 + ], + [ + 'product_id' => 13, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 2 + ] + ], + [ + [ + 'product_id' => 10, + 'selection_qty' => 10, + 'delete' => '', + 'option_id' => 3 + ], + [ + 'product_id' => 11, + 'selection_qty' => 10, + 'delete' => '', + 'option_id' => 3 + ], + [ + 'product_id' => 14, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 3 + ] + ], + [ + [ + 'product_id' => 13, + 'selection_qty' => 10, + 'delete' => '', + 'option_id' => 4 + ], + [ + 'product_id' => 14, + 'selection_qty' => 10, + 'delete' => '', + 'option_id' => 4 + ], + [ + 'product_id' => 12, + 'selection_qty' => 10, + 'selection_can_change_qty' => 0, + 'delete' => '', + 'option_id' => 4 + ] + ], + [ + [ + 'product_id' => 10, + 'selection_qty' => 10, + 'delete' => '', + 'option_id' => 5 + ], + [ + 'product_id' => 11, + 'selection_qty' => 10, + 'delete' => '', + 'option_id' => 5 + ] + ] + ] + ); + +if ($product->getBundleOptionsData()) { + $options = []; + foreach ($product->getBundleOptionsData() as $key => $optionData) { + if (!(bool)$optionData['delete']) { + $option = $objectManager->create(\Magento\Bundle\Api\Data\OptionInterfaceFactory::class) + ->create(['data' => $optionData]); + $option->setSku($product->getSku()); + $option->setOptionId(null); + + $links = []; + $bundleLinks = $product->getBundleSelectionsData(); + if (!empty($bundleLinks[$key])) { + foreach ($bundleLinks[$key] as $linkData) { + if (!(bool)$linkData['delete']) { + $link = $objectManager->create(\Magento\Bundle\Api\Data\LinkInterfaceFactory::class) + ->create(['data' => $linkData]); + $linkProduct = $productRepository->getById($linkData['product_id']); + $link->setSku($linkProduct->getSku()); + $link->setQty($linkData['selection_qty']); + $links[] = $link; + } + } + $option->setProductLinks($links); + $options[] = $option; + } + } + } + $extension = $product->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $product->setExtensionAttributes($extension); +} + +$productRepository->save($product, true); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/issaleable_product_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/issaleable_product_rollback.php new file mode 100644 index 0000000000000..3354c7962babf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/issaleable_product_rollback.php @@ -0,0 +1,28 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var $product \Magento\Catalog\Model\Product */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +try { + $product = $productRepository->get('bundle-product'); + $productRepository->delete($product); +} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed +} + + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/multiple_products.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/multiple_products.php new file mode 100644 index 0000000000000..4624fc65e4ab8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/multiple_products.php @@ -0,0 +1,129 @@ +create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(10) + ->setAttributeSetId(4) + ->setName('Simple Product') + ->setSku('simple1') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_IN_CART) + ->setPrice(10) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCateroryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + +$productRepository->save($product); + +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(11) + ->setAttributeSetId(4) + ->setName('Simple Product2') + ->setSku('simple2') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_ON_GESTURE) + ->setPrice(20) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCateroryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + +$productRepository->save($product); + +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(12) + ->setAttributeSetId(4) + ->setName('Simple Product 3') + ->setSku('simple3') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setPrice(30) + ->setWeight(1) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCateroryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 140, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + +$productRepository->save($product); + +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(13) + ->setAttributeSetId(4) + ->setName('Simple Product 4') + ->setSku('simple4') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_IN_CART) + ->setPrice(13) + ->setWeight(12) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCateroryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 20, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + +$productRepository->save($product); + +$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(14) + ->setAttributeSetId(4) + ->setName('Simple Product 5') + ->setSku('simple5') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(\Magento\Msrp\Model\Product\Attribute\Source\Type::TYPE_IN_CART) + ->setPrice(14) + ->setWeight(10) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCateroryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 15, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/multiple_products_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/multiple_products_rollback.php new file mode 100644 index 0000000000000..544b213c853e5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/multiple_products_rollback.php @@ -0,0 +1,28 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +foreach (['simple1', 'simple2', 'simple3', 'simple4', 'simple5'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed + } +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php index 59426d9a7ac29..b691730cd87f4 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_item_with_bundle_and_options.php @@ -1,6 +1,6 @@ \Magento\Customer\Model\GroupManagement::CUST_GROUP_ALL, 'price_qty' => 2, 'price' => 8, + 'percentage_value' => 8 ], [ 'website_id' => 0, 'cust_group' => \Magento\Customer\Model\GroupManagement::CUST_GROUP_ALL, 'price_qty' => 5, 'price' => 30, + 'percentage_value' => 30 ], [ 'website_id' => 0, 'cust_group' => \Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID, 'price_qty' => 3, 'price' => 20, + 'percentage_value' => 20 ], ] ) diff --git a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/BundleTest.php b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/BundleTest.php index 1906c9d48e0b6..af48e160316f8 100644 --- a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/BundleTest.php +++ b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/BundleTest.php @@ -1,6 +1,6 @@ .?/' + . ',text_attribute2=,'; + $allAdditionalAttributes = $parsedAdditionalAttributes . ',weight_type=0,price_type=1'; /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ $collection = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product\Collection::class); $select = $collection->getConnection()->select() @@ -42,7 +45,7 @@ public function testPrepareData() $select = (string)$collection->getSelect(); $this->model->prepareData($collection, array_values($ids)); $this->assertEquals($select, (string)$collection->getSelect()); - $result = $this->model->addData([], $ids['bundle-product']); + $result = $this->model->addData(['additional_attributes' => $allAdditionalAttributes], $ids['bundle-product']); $this->assertArrayHasKey('bundle_price_type', $result); $this->assertArrayHasKey('bundle_shipment_type', $result); $this->assertArrayHasKey('bundle_sku_type', $result); @@ -51,5 +54,6 @@ public function testPrepareData() $this->assertArrayHasKey('bundle_values', $result); $this->assertContains('sku=simple,', $result['bundle_values']); $this->assertEquals([], $this->model->addData([], $ids['simple'])); + $this->assertEquals($parsedAdditionalAttributes, $result['additional_attributes']); } } diff --git a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php index 9a7024c4b63df..d54ba8e628e93 100644 --- a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php +++ b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php @@ -1,6 +1,6 @@ true, 'meta_title' => true, 'custom_design' => true, - 'page_layout' => false, + 'page_layout' => true, 'is_active' => true, 'include_in_menu' => true, 'landing_page' => true, @@ -242,7 +242,7 @@ public function saveActionDataProvider() 'description' => true, 'meta_keywords' => true, 'meta_description' => true, - 'custom_layout_update' => false, + 'custom_layout_update' => true, 'custom_design_from' => true, 'custom_design_to' => true, 'filter_price_range' => false diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Action/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Action/AttributeTest.php index fc2763aea017d..92e932b3ac214 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Action/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/Action/AttributeTest.php @@ -1,6 +1,6 @@ assertTrue($isRedirectPresent); } + /** + * @covers \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute\Save::execute + * + * @dataProvider saveActionVisibilityAttrDataProvider + * @param array $attributes + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testSaveActionChangeVisibility($attributes) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ProductRepository::class + ); + $product = $repository->get('simple'); + $product->setOrigData(); + $product->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_NOT_VISIBLE); + $product->save(); + + /** @var $session \Magento\Backend\Model\Session */ + $session = $objectManager->get(\Magento\Backend\Model\Session::class); + $session->setProductIds([$product->getId()]); + $this->getRequest()->setParam('attributes', $attributes); + + $this->dispatch('backend/catalog/product_action_attribute/save/store/0'); + /** @var \Magento\Catalog\Model\Category $category */ + $categoryFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Catalog\Model\CategoryFactory::class + ); + /** @var \Magento\Catalog\Block\Product\ListProduct $listProduct */ + $listProduct = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Catalog\Block\Product\ListProduct::class + ); + + $category = $categoryFactory->create()->load(2); + $layer = $listProduct->getLayer(); + $layer->setCurrentCategory($category); + $productCollection = $layer->getProductCollection(); + $productItem = $productCollection->getFirstItem(); + $this->assertEquals($session->getProductIds(), [$productItem->getId()]); + } + /** * @covers \Magento\Catalog\Controller\Adminhtml\Product\Action\Attribute\Validate::execute * @@ -97,4 +138,17 @@ public function validateActionDataProvider() ] ]; } + + /** + * Data Provider for save with visibility attribute + * + * @return array + */ + public function saveActionVisibilityAttrDataProvider() + { + return [ + ['arguments' => ['visibility' => \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH]], + ['arguments' => ['visibility' => \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG]] + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php index 5b08ab5b1690e..8fbea95ea7ad8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/Product/AttributeTest.php @@ -1,6 +1,6 @@ getAttributeSetByName('attribute_set_test'); + $this->assertNotEmpty($attributeSet, 'Attribute set with name "attribute_set_test" is missed'); + + $this->getRequest()->setPostValue('data', json_encode([ + 'attribute_set_name' => 'attribute_set_test', + 'groups' => [ + ['ynode-418', 'attribute-group-name', 1], + ], + 'attributes' => [ + ['9999', 'ynode-418', 1, null] + ], + 'not_attributes' => [], + 'removeGroups' => [], + ])); + $this->dispatch('backend/catalog/product_set/save/id/' . $attributeSet->getAttributeSetId()); + + $jsonResponse = json_decode($this->getResponse()->getBody()); + $this->assertNotNull($jsonResponse); + $this->assertEquals(1, $jsonResponse->error); + $this->assertContains( + 'Attribute group with same code already exist. Please rename "attribute-group-name" group', + $jsonResponse->message + ); + } + + /** + * @param string $attributeSetName + * @return AttributeSetInterface|null + */ + protected function getAttributeSetByName($attributeSetName) + { + $objectManager = Bootstrap::getObjectManager(); + + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class); + $searchCriteriaBuilder->addFilter('attribute_set_name', $attributeSetName); + + /** @var AttributeSetRepositoryInterface $attributeSetRepository */ + $attributeSetRepository = $objectManager->get(AttributeSetRepositoryInterface::class); + $result = $attributeSetRepository->getList($searchCriteriaBuilder->create()); + + $items = $result->getItems(); + return $result->getTotalCount() ? array_pop($items) : null; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php index bde98c84d89bb..7e1e320293fdc 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + $this->store = $this->objectManager->create(\Magento\Store\Model\Store::class); + $this->cron = $this->objectManager->create(\Magento\Catalog\Cron\DeleteOutdatedPriceValues::class); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoConfigFixture current_store catalog/price/scope 1 + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testExecute() + { + $secondStoreId = $this->store->load('fixture_second_store')->getId(); + /** @var \Magento\Catalog\Model\Product\Action $productAction */ + $productAction = $this->objectManager->create( + \Magento\Catalog\Model\Product\Action::class + ); + /** @var ReinitableConfigInterface $reinitiableConfig */ + $reinitiableConfig = $this->objectManager->get(ReinitableConfigInterface::class); + $reinitiableConfig->setValue( + 'catalog/price/scope', + \Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE + ); + $observer = $this->objectManager->get(\Magento\Framework\Event\Observer::class); + $this->objectManager->get(SwitchPriceAttributeScopeOnConfigChange::class) + ->execute($observer); + + $reflection = new \ReflectionClass(\Magento\Catalog\Model\Attribute\ScopeOverriddenValue::class); + $paths = $reflection->getProperty('attributesValues'); + $paths->setAccessible(true); + $paths->setValue($this->objectManager->get(\Magento\Catalog\Model\Attribute\ScopeOverriddenValue::class), null); + $paths->setAccessible(false); + + $product = $this->productRepository->get('simple'); + $productResource = $this->objectManager->create(\Magento\Catalog\Model\ResourceModel\Product::class); + + $productId = $product->getId(); + $productAction->updateWebsites( + [$productId], + [$this->store->load('fixture_second_store')->getWebsiteId()], + 'add' + ); + $product->setStoreId($secondStoreId); + $product->setPrice(9.99); + + $productResource->save($product); + $attribute = $this->objectManager->get(\Magento\Eav\Model\Config::class) + ->getAttribute( + 'catalog_product', + 'price' + ); + $this->assertEquals( + '9.99', + $productResource->getAttributeRawValue($productId, $attribute->getId(), $secondStoreId) + ); + /** @var MutableScopeConfigInterface $config */ + $config = $this->objectManager->get( + MutableScopeConfigInterface::class + ); + $config->setValue( + \Magento\Store\Model\Store::XML_PATH_PRICE_SCOPE, + \Magento\Store\Model\Store::PRICE_SCOPE_GLOBAL, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + /** @var \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig */ + $this->cron->execute(); + $this->assertEquals( + '10.0000', + $productResource->getAttributeRawValue($productId, $attribute->getId(), $secondStoreId) + ); + } + + public function tearDown() + { + parent::tearDown(); + /** @var ReinitableConfigInterface $reinitiableConfig */ + $reinitiableConfig = $this->objectManager->get(ReinitableConfigInterface::class); + $reinitiableConfig->setValue( + 'catalog/price/scope', + \Magento\Store\Model\Store::PRICE_SCOPE_GLOBAL + ); + $observer = $this->objectManager->get(\Magento\Framework\Event\Observer::class); + $this->objectManager->get(SwitchPriceAttributeScopeOnConfigChange::class) + ->execute($observer); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Helper/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Helper/CategoryTest.php index 4cf7f56c0d807..12accd36b5e4e 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Helper/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Helper/CategoryTest.php @@ -1,6 +1,6 @@ [ (new \Magento\Framework\DataObject())->setPrice(3.256)->setRoundPrice(true), - '2.67', + '2.97', [ [ 'path' => Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX, diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Helper/OutputTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Helper/OutputTest.php index 4dd6d1cfc4885..cff79f237ab80 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Helper/OutputTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Helper/OutputTest.php @@ -1,6 +1,6 @@ assertFalse($this->_state->isFlatEnabled()); - } - /** * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 */ diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/Stub/ProductControllerStub.php b/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/Stub/ProductControllerStub.php index 42a9735ea2f09..7715598192ead 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/Stub/ProductControllerStub.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Helper/Product/Stub/ProductControllerStub.php @@ -1,6 +1,6 @@ magentoDataFixture -> magentoConfigFixture - * (https://wiki.magento.com/display/PAAS/Integration+Tests+Development+Guide - * #IntegrationTestsDevelopmentGuide-ApplyingAnnotations) - * config fixtures can't be applied before data fixture. - */ -namespace Magento\Catalog\Model\Category; - -use Magento\Catalog\Model\Category\CategoryImageTest\StubZendLogWriterStream; - -class CategoryImageTest extends \PHPUnit_Framework_TestCase -{ - /** @var int */ - protected $_oldLogActive; - - /** @var string */ - protected $_oldExceptionFile; - - /** @var string */ - protected $_oldWriterModel; - - protected function setUp() - { - $this->_oldLogActive = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Store\Model\StoreManagerInterface::class - )->getStore()->getConfig( - 'dev/log/active' - ); - $this->_oldExceptionFile = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Store\Model\StoreManagerInterface::class - )->getStore()->getConfig( - 'dev/log/exception_file' - ); - } - - protected function tearDown() - { - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class - )->setValue( - 'dev/log/active', - $this->_oldLogActive, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); - - $this->_oldLogActive = null; - - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class - )->setValue( - 'dev/log/exception_file', - $this->_oldExceptionFile, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); - - $this->_oldExceptionFile = null; - - $this->_oldWriterModel = null; - - /** - * @TODO: refactor this test - * Changing store configuration in such a way totally breaks the idea of application isolation. - * Class declaration in data fixture file is dumb too. - * Added a quick fix to be able run separate tests with "phpunit --filter testMethod" - */ - if (class_exists(\Magento\Catalog\Model\Category\CategoryImageTest\StubZendLogWriterStreamTest::class, false)) { - StubZendLogWriterStream::$exceptions = []; - } - } - - /** - * Test that there is no exception '$_FILES array is empty' in \Magento\Framework\File\Uploader::_setUploadFileId() - * if category image was not set - * - */ - public function testSaveCategoryWithoutImage() - { - $this->markTestSkipped('MAGETWO-15096'); - - /** @var $objectManager \Magento\TestFramework\ObjectManager */ - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - - /** @var $category \Magento\Catalog\Model\Category */ - $category = $objectManager->get(\Magento\Framework\Registry::class) - ->registry('_fixture/Magento\Catalog\Model\Category'); - $this->assertNotEmpty($category->getId()); - - foreach (StubZendLogWriterStream::$exceptions as $exception) { - $this->assertNotContains('$_FILES array is empty', $exception['message']); - } - } -} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/CategoryImageTest/StubZendLogWriterStream.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/CategoryImageTest/StubZendLogWriterStream.php deleted file mode 100644 index 3915ad47b3b1c..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/CategoryImageTest/StubZendLogWriterStream.php +++ /dev/null @@ -1,34 +0,0 @@ -get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class -)->setValue( - 'dev/log/active', - 1, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE -); - -\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class -)->setValue( - 'dev/log/exception_file', - 'save_category_without_image.log', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE -); -class StubZendLogWriterStream extends \Zend_Log_Writer_Stream -{ - /** @var array */ - public static $exceptions = []; - - public function write($event) - { - self::$exceptions[] = $event; - - parent::write($event); - } -} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/DataProviderTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/DataProviderTest.php index a3fb25f0e16c7..7141318db2d16 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/DataProviderTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/DataProviderTest.php @@ -1,6 +1,6 @@ assertEquals('5', $category->getPosition()); } + /** + * @magentoDbIsolation enabled + */ + public function testSaveCategoryWithoutImage() + { + $model = $this->objectManager->create(\Magento\Catalog\Model\Category::class); + $repository = $this->objectManager->get(\Magento\Catalog\Api\CategoryRepositoryInterface::class); + + $model->setName('Test Category 100') + ->setParentId(2) + ->setLevel(2) + ->setAvailableSortBy(['position', 'name']) + ->setDefaultSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->isObjectNew(true); + + $repository->save($model); + $this->assertEmpty($model->getImage()); + } + /** * @magentoAppArea adminhtml */ diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php index fd8c9cace6b11..26d98c20552bb 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->config = $this->objectManager->get(Config::class); + } + + public function testGetEntityAttributeCodes() + { + $entityType = 'catalog_product'; + CacheCleaner::cleanAll(); + $this->assertEquals( + $this->config->getEntityAttributeCodes($entityType), + $this->config->getEntityAttributeCodes($entityType) + ); + } + + public function testGetAttribute() + { + $entityType = 'catalog_product'; + $attributeCode = 'color'; + CacheCleaner::cleanAll(); + $this->assertEquals( + $this->config->getAttribute($entityType, $attributeCode), + $this->config->getAttribute($entityType, $attributeCode) + ); + } + + public function testGetEntityType() + { + $entityType = 'catalog_product'; + CacheCleaner::cleanAll(); + $this->assertEquals( + $this->config->getEntityType($entityType), + $this->config->getEntityType($entityType) + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php index 2c144c2ff9a25..960ba6f730837 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/DesignTest.php @@ -1,6 +1,6 @@ getCollection()->getItems(); + $result = $category->getCollection()->addAttributeToSelect('name')->getItems(); $result = array_slice($result, 2); return array_slice($result, 0, $count); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/FlatTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/FlatTest.php index 414f389fe8a25..080f5cebbb383 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/FlatTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/FlatTest.php @@ -1,6 +1,6 @@ _model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var ReinitableConfigInterface $reinitiableConfig */ + $reinitiableConfig = $this->objectManager->get(ReinitableConfigInterface::class); + $reinitiableConfig->setValue( + 'catalog/price/scope', + \Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE + ); + $observer = $this->objectManager->get(\Magento\Framework\Event\Observer::class); + $this->objectManager->get(SwitchPriceAttributeScopeOnConfigChange::class) + ->execute($observer); + + $this->model = $this->objectManager->create( \Magento\Catalog\Model\Product\Attribute\Backend\Price::class ); - $this->_model->setAttribute( - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + $this->productRepository = $this->objectManager->create( + ProductRepositoryInterface::class + ); + $this->model->setAttribute( + $this->objectManager->get( \Magento\Eav\Model\Config::class )->getAttribute( 'catalog_product', @@ -37,50 +65,247 @@ public function testSetScopeDefault() /* validate result of setAttribute */ $this->assertEquals( \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - $this->_model->getAttribute()->getIsGlobal() + $this->model->getAttribute()->getIsGlobal() ); - $this->_model->setScope($this->_model->getAttribute()); + $this->model->setScope($this->model->getAttribute()); $this->assertEquals( \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - $this->_model->getAttribute()->getIsGlobal() + $this->model->getAttribute()->getIsGlobal() ); } /** + * @magentoDbIsolation enabled * @magentoConfigFixture current_store catalog/price/scope 1 */ public function testSetScope() { - $this->_model->setScope($this->_model->getAttribute()); + $this->model->setScope($this->model->getAttribute()); $this->assertEquals( \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, - $this->_model->getAttribute()->getIsGlobal() + $this->model->getAttribute()->getIsGlobal() ); } /** + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Catalog/_files/product_simple.php * @magentoConfigFixture current_store catalog/price/scope 1 * @magentoConfigFixture current_store currency/options/base GBP */ public function testAfterSave() { - $repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\ProductRepository::class + /** @var \Magento\Store\Model\Store $store */ + $store = $this->objectManager->create(\Magento\Store\Model\Store::class); + $globalStoreId = $store->load('admin')->getId(); + $product = $this->productRepository->get('simple'); + $product->setPrice('9.99'); + $product->setStoreId($globalStoreId); + $product->getResource()->save($product); + $product = $this->productRepository->get('simple', false, $globalStoreId, true); + $this->assertEquals('9.99', $product->getPrice()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoConfigFixture current_store catalog/price/scope 1 + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + */ + public function testAfterSaveWithDifferentStores() + { + /** @var \Magento\Store\Model\Store $store */ + $store = $this->objectManager->create( + \Magento\Store\Model\Store::class + ); + $globalStoreId = $store->load('admin')->getId(); + $secondStoreId = $store->load('fixture_second_store')->getId(); + $thirdStoreId = $store->load('fixture_third_store')->getId(); + /** @var \Magento\Catalog\Model\Product\Action $productAction */ + $productAction = $this->objectManager->create( + \Magento\Catalog\Model\Product\Action::class + ); + + $product = $this->productRepository->get('simple'); + $productId = $product->getId(); + $productAction->updateWebsites([$productId], [$store->load('fixture_second_store')->getWebsiteId()], 'add'); + $product->setStoreId($secondStoreId); + $product->setPrice('9.99'); + $product->getResource()->save($product); + + $product = $this->productRepository->get('simple', false, $globalStoreId, true); + $this->assertEquals(10, $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $secondStoreId, true); + $this->assertEquals('9.99', $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $thirdStoreId, true); + $this->assertEquals('9.99', $product->getPrice()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoConfigFixture current_store catalog/price/scope 1 + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + */ + public function testAfterSaveWithSameCurrency() + { + /** @var \Magento\Store\Model\Store $store */ + $store = $this->objectManager->create( + \Magento\Store\Model\Store::class + ); + $globalStoreId = $store->load('admin')->getId(); + $secondStoreId = $store->load('fixture_second_store')->getId(); + $thirdStoreId = $store->load('fixture_third_store')->getId(); + /** @var \Magento\Catalog\Model\Product\Action $productAction */ + $productAction = $this->objectManager->create( + \Magento\Catalog\Model\Product\Action::class ); - $product = $repository->get('simple'); + + $product = $this->productRepository->get('simple'); + $productId = $product->getId(); + $productAction->updateWebsites([$productId], [$store->load('fixture_second_store')->getWebsiteId()], 'add'); $product->setOrigData(); - $product->setPrice(9.99); - $product->setStoreId(0); - $product->save(); - $this->assertEquals( - '9.99', - $product->getResource()->getAttributeRawValue( - $product->getId(), - $this->_model->getAttribute()->getId(), - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Store\Model\StoreManagerInterface::class - )->getStore()->getId() - ) + $product->setStoreId($secondStoreId); + $product->setPrice('9.99'); + $product->getResource()->save($product); + + $product = $this->productRepository->get('simple', false, $globalStoreId, true); + $this->assertEquals(10, $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $secondStoreId, true); + $this->assertEquals('9.99', $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $thirdStoreId, true); + $this->assertEquals('9.99', $product->getPrice()); + } + + /** + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoConfigFixture current_store catalog/price/scope 1 + */ + public function testAfterSaveWithUseDefault() + { + /** @var \Magento\Store\Model\Store $store */ + $store = $this->objectManager->create( + \Magento\Store\Model\Store::class + ); + $globalStoreId = $store->load('admin')->getId(); + $secondStoreId = $store->load('fixture_second_store')->getId(); + $thirdStoreId = $store->load('fixture_third_store')->getId(); + /** @var \Magento\Catalog\Model\Product\Action $productAction */ + $productAction = $this->objectManager->create( + \Magento\Catalog\Model\Product\Action::class + ); + + $product = $this->productRepository->get('simple'); + $productId = $product->getId(); + $productAction->updateWebsites([$productId], [$store->load('fixture_second_store')->getWebsiteId()], 'add'); + $product->setOrigData(); + $product->setStoreId($secondStoreId); + $product->setPrice('9.99'); + $product->getResource()->save($product); + + $product = $this->productRepository->get('simple', false, $globalStoreId, true); + $this->assertEquals(10, $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $secondStoreId, true); + $this->assertEquals('9.99', $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $thirdStoreId, true); + $this->assertEquals('9.99', $product->getPrice()); + + $product->setStoreId($thirdStoreId); + $product->setPrice(null); + $product->getResource()->save($product); + + $product = $this->productRepository->get('simple', false, $globalStoreId, true); + $this->assertEquals(10, $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $secondStoreId, true); + $this->assertEquals(10, $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $thirdStoreId, true); + $this->assertEquals(10, $product->getPrice()); + } + + /** + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoConfigFixture default_store catalog/price/scope 1 + */ + public function testAfterSaveForWebsitesWithDifferentCurrencies() + { + /** @var \Magento\Store\Model\Store $store */ + $store = $this->objectManager->create( + \Magento\Store\Model\Store::class + ); + + /** @var \Magento\Directory\Model\ResourceModel\Currency $rate */ + $rate = $this->objectManager->create(\Magento\Directory\Model\ResourceModel\Currency::class); + $rate->saveRates([ + 'USD' => ['EUR' => 2], + 'EUR' => ['USD' => 0.5] + ]); + + $globalStoreId = $store->load('admin')->getId(); + $secondStore = $store->load('fixture_second_store'); + $secondStoreId = $store->load('fixture_second_store')->getId(); + $thirdStoreId = $store->load('fixture_third_store')->getId(); + + /** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */ + $config = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $config->setValue( + 'currency/options/default', + 'EUR', + \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITES, + 'test' + ); + + $productAction = $this->objectManager->create( + \Magento\Catalog\Model\Product\Action::class + ); + $product = $this->productRepository->get('simple'); + $productId = $product->getId(); + $productAction->updateWebsites([$productId], [$secondStore->getWebsiteId()], 'add'); + $product->setOrigData(); + $product->setStoreId($globalStoreId); + $product->setPrice(100); + $product->getResource()->save($product); + + $product = $this->productRepository->get('simple', false, $globalStoreId, true); + $this->assertEquals(100, $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $secondStoreId, true); + $this->assertEquals(100, $product->getPrice()); + + $product = $this->productRepository->get('simple', false, $thirdStoreId, true); + $this->assertEquals(100, $product->getPrice()); + } + + public static function tearDownAfterClass() + { + parent::tearDownAfterClass(); + /** @var ReinitableConfigInterface $reinitiableConfig */ + $reinitiableConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + ReinitableConfigInterface::class + ); + $reinitiableConfig->setValue( + 'catalog/price/scope', + \Magento\Store\Model\Store::PRICE_SCOPE_GLOBAL + ); + $observer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\Event\Observer::class ); + \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(SwitchPriceAttributeScopeOnConfigChange::class) + ->execute($observer); } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php index 88390103a0f48..05bc770623900 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/SkuTest.php @@ -1,6 +1,6 @@ _model->validate($product); } + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testValidatePercentage() + { + $product = new \Magento\Framework\DataObject(); + $product->setTierPrice( + [ + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'percentage_value' => 101], + ] + ); + + $this->_model->validate($product); + } + public function testPreparePriceData() { $data = [ @@ -122,7 +137,7 @@ public function testAfterLoad() $this->_model->afterLoad($product); $price = $product->getTierPrice(); $this->assertNotEmpty($price); - $this->assertEquals(3, count($price)); + $this->assertEquals(4, count($price)); } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Source/CountryofmanufactureTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Source/CountryofmanufactureTest.php new file mode 100644 index 0000000000000..392a64081c1e9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Source/CountryofmanufactureTest.php @@ -0,0 +1,32 @@ +model = $objectManager->create( + \Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture::class + ); + } + + public function testGetAllOptions() + { + CacheCleaner::cleanAll(); + $allOptions = $this->model->getAllOptions(); + $cachedAllOptions = $this->model->getAllOptions(); + $this->assertEquals($allOptions, $cachedAllOptions); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/create_attribute_service.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/create_attribute_service.php index 2a0cd37c68d37..1e805048885be 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/create_attribute_service.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/_files/create_attribute_service.php @@ -1,5 +1,5 @@ createHandler = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( @@ -28,10 +32,8 @@ protected function setUp() /** * @covers \Magento\Catalog\Model\Product\Gallery\CreateHandler::execute */ - public function testExecute() + public function testExecuteWithImageDuplicate() { - $fileName = '/m/a/magento_image.jpg'; - $fileLabel = 'Magento image'; /** @var $product \Magento\Catalog\Model\Product */ $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Catalog\Model\Product::class @@ -39,20 +41,141 @@ public function testExecute() $product->load(1); $product->setData( 'media_gallery', - ['images' => ['image' => ['file' => $fileName, 'label' => $fileLabel]]] + ['images' => ['image' => ['file' => $this->fileName, 'label' => $this->fileLabel]]] ); - $product->setData('image', $fileName); + $product->setData('image', $this->fileName); $this->createHandler->execute($product); $this->assertStringStartsWith('/m/a/magento_image', $product->getData('media_gallery/images/image/new_file')); - $this->assertEquals($fileLabel, $product->getData('image_label')); + $this->assertEquals($this->fileLabel, $product->getData('image_label')); $product->setIsDuplicate(true); $product->setData( 'media_gallery', - ['images' => ['image' => ['value_id' => '100', 'file' => $fileName, 'label' => $fileLabel]]] + ['images' => ['image' => ['value_id' => '100', 'file' => $this->fileName, 'label' => $this->fileLabel]]] ); $this->createHandler->execute($product); $this->assertStringStartsWith('/m/a/magento_image', $product->getData('media_gallery/duplicate/100')); - $this->assertEquals($fileLabel, $product->getData('image_label')); + $this->assertEquals($this->fileLabel, $product->getData('image_label')); + } + + /** + * @dataProvider executeDataProvider + * @param $image + * @param $smallImage + * @param $swatchImage + * @param $thumbnail + */ + public function testExecuteWithImageRoles($image, $smallImage, $swatchImage, $thumbnail) + { + /** @var $product \Magento\Catalog\Model\Product */ + $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\Product::class + ); + $product->load(1); + $product->setData( + 'media_gallery', + ['images' => ['image' => ['file' => $this->fileName, 'label' => '']]] + ); + $product->setData('image', $image); + $product->setData('small_image', $smallImage); + $product->setData('swatch_image', $swatchImage); + $product->setData('thumbnail', $thumbnail); + $this->createHandler->execute($product); + + $resource = $product->getResource(); + $id = $product->getId(); + $storeId = $product->getStoreId(); + + $this->assertStringStartsWith('/m/a/magento_image', $product->getData('media_gallery/images/image/new_file')); + $this->assertEquals( + $image, + $resource->getAttributeRawValue($id, $resource->getAttribute('image'), $storeId) + ); + $this->assertEquals( + $smallImage, + $resource->getAttributeRawValue($id, $resource->getAttribute('small_image'), $storeId) + ); + $this->assertEquals( + $swatchImage, + $resource->getAttributeRawValue($id, $resource->getAttribute('swatch_image'), $storeId) + ); + $this->assertEquals( + $thumbnail, + $resource->getAttributeRawValue($id, $resource->getAttribute('thumbnail'), $storeId) + ); + } + + /** + * @dataProvider executeDataProvider + * @param $image + * @param $smallImage + * @param $swatchImage + * @param $thumbnail + */ + public function testExecuteWithoutImages($image, $smallImage, $swatchImage, $thumbnail) + { + /** @var $product \Magento\Catalog\Model\Product */ + $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\Product::class + ); + $product->load(1); + $product->setData( + 'media_gallery', + ['images' => ['image' => ['file' => $this->fileName, 'label' => '']]] + ); + $product->setData('image', $image); + $product->setData('small_image', $smallImage); + $product->setData('swatch_image', $swatchImage); + $product->setData('thumbnail', $thumbnail); + $this->createHandler->execute($product); + + $product->unsetData('image'); + $product->unsetData('small_image'); + $product->unsetData('swatch_image'); + $product->unsetData('thumbnail'); + $this->createHandler->execute($product); + + $resource = $product->getResource(); + $id = $product->getId(); + $storeId = $product->getStoreId(); + + $this->assertStringStartsWith('/m/a/magento_image', $product->getData('media_gallery/images/image/new_file')); + $this->assertEquals( + $image, + $resource->getAttributeRawValue($id, $resource->getAttribute('image'), $storeId) + ); + $this->assertEquals( + $smallImage, + $resource->getAttributeRawValue($id, $resource->getAttribute('small_image'), $storeId) + ); + $this->assertEquals( + $swatchImage, + $resource->getAttributeRawValue($id, $resource->getAttribute('swatch_image'), $storeId) + ); + $this->assertEquals( + $thumbnail, + $resource->getAttributeRawValue($id, $resource->getAttribute('thumbnail'), $storeId) + ); + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + [ + 'image' => $this->fileName, + 'small_image' => $this->fileName, + 'swatch_image' => $this->fileName, + 'thumbnail' => $this->fileName + ], + [ + 'image' => 'no_selection', + 'small_image' => 'no_selection', + 'swatch_image' => 'no_selection', + 'thumbnail' => 'no_selection' + ] + ]; } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php index 9c9e564939070..6bd57c5c8eeee 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ProcessorTest.php @@ -1,6 +1,6 @@ setData(['image' => 'test1', 'small_image' => 'test2', 'thumbnail' => 'test3']); - $this->assertNotEmpty($product->getData('image')); + $this->assertNotEquals('no_selection', $product->getData('image')); $this->_model->clearMediaAttribute($product, 'image'); - $this->assertNull($product->getData('image')); + $this->assertEquals('no_selection', $product->getData('image')); - $this->assertNotEmpty($product->getData('small_image')); - $this->assertNotEmpty($product->getData('thumbnail')); + $this->assertNotEquals('no_selection', $product->getData('small_image')); + $this->assertNotEquals('no_selection', $product->getData('thumbnail')); $this->_model->clearMediaAttribute($product, ['small_image', 'thumbnail']); - $this->assertNull($product->getData('small_image')); - $this->assertNull($product->getData('thumbnail')); + $this->assertEquals('no_selection', $product->getData('small_image')); + $this->assertEquals('no_selection', $product->getData('thumbnail')); } public function testSetMediaAttribute() diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ReadHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ReadHandlerTest.php index 8a14d1e6a858c..75efbb5a49726 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ReadHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/ReadHandlerTest.php @@ -1,6 +1,6 @@ assertArrayHasKey('media_gallery', $data); $this->assertArrayHasKey('images', $data['media_gallery']); - $image = array_shift($data['media_gallery']['images']); - $this->assertEquals( - 'Image Alt Text', - $image['label'] - ); + $this->assertCount(1, $data['media_gallery']['images']); + foreach ($data['media_gallery']['images'] as $valueId => $imageData) { + $this->assertEquals( + 'Image Alt Text', + $imageData['label'] + ); + $this->assertEquals( + $imageData['value_id'], + $valueId + ); + } } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ImageTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ImageTest.php index 688dc42958b0b..16d40ae32d68d 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ImageTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ImageTest.php @@ -1,6 +1,6 @@ create( \Magento\Catalog\Model\Product\Image::class ); - $model->setDestinationSubdir('image')->setBaseFile(''); - $this->assertEmpty($model->getBaseFile()); + /** @var \Magento\Catalog\Model\View\Asset\Placeholder $defualtPlaceholder */ + $defualtPlaceholder = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Model\View\Asset\Placeholder::class, + ['type' => 'image'] + ); + + $model->setDestinationSubdir('image'); + $model->setBaseFile(''); + $this->assertEquals($defualtPlaceholder->getSourceFile(), $model->getBaseFile()); return $model; } @@ -46,7 +53,7 @@ public function testSaveFilePlaceholder($model) public function testGetUrlPlaceholder($model) { $this->assertStringMatchesFormat( - 'http://localhost/pub/static/frontend/%s/Magento_Catalog/images/product/placeholder/image.jpg', + 'http://localhost/pub/static/%s/frontend/%s/Magento_Catalog/images/product/placeholder/image.jpg', $model->getUrl() ); } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/DateTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/DateTest.php new file mode 100644 index 0000000000000..9e8aec999e76b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/DateTest.php @@ -0,0 +1,112 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $this->objectManager->create( + \Magento\Catalog\Model\Product\Option\Type\Date::class + ); + } + + /** + * @covers \Magento\Catalog\Model\Product\Option\Type\Date::prepareOptionValueForRequest() + * @dataProvider prepareOptionValueForRequestDataProvider + * @param array $optionValue + * @param array $infoBuyRequest + * @param array $expectedOptionValueForRequest + * @param array $productOptionData + */ + public function testPrepareOptionValueForRequest( + array $optionValue, + array $infoBuyRequest, + array $productOptionData, + array $expectedOptionValueForRequest + ) { + /** @var \Magento\Quote\Model\Quote\Item\Option $option */ + $option = $this->objectManager->create( + \Magento\Quote\Model\Quote\Item\Option::class, + ['data' => $infoBuyRequest] + ); + /** @var \Magento\Quote\Model\Quote\Item $item */ + $item = $this->objectManager->create(\Magento\Quote\Model\Quote\Item::class); + $item->addOption($option); + /** @var \Magento\Catalog\Model\Product\Option|null $productOption */ + $productOption = $productOptionData + ? $this->objectManager->create( + \Magento\Catalog\Model\Product\Option::class, + ['data' => $productOptionData] + ) + : null; + $this->model->setData('quote_item', $item); + $this->model->setOption($productOption); + + $actualOptionValueForRequest = $this->model->prepareOptionValueForRequest($optionValue); + $this->assertSame($expectedOptionValueForRequest, $actualOptionValueForRequest); + } + + /** + * @return array + */ + public function prepareOptionValueForRequestDataProvider() + { + return [ + // Variation 1 + [ + // $optionValue + ['field1' => 'value1', 'field2' => 'value2'], + // $infoBuyRequest + ['code' => 'info_buyRequest', 'value' => '{"qty":23}'], + // $productOptionData + ['id' => '11', 'value' => '{"qty":12}'], + // $expectedOptionValueForRequest + ['date_internal' => ['field1' => 'value1', 'field2' => 'value2']] + ], + // Variation 2 + [ + // $optionValue + ['field1' => 'value1', 'field2' => 'value2'], + // $infoBuyRequest + ['code' => 'info_buyRequest', 'value' => '{"options":{"11":{"qty":23}}}'], + // $productOptionData + ['id' => '11', 'value' => '{"qty":12}'], + // $expectedOptionValueForRequest + ['qty' => 23] + ], + // Variation 3 + [ + // $optionValue + ['field1' => 'value1', 'field2' => 'value2'], + // $infoBuyRequest + ['code' => 'info_buyRequest', 'value' => '{"options":{"11":{"qty":23}}}'], + // $productOptionData + [], + // $expectedOptionValueForRequest + ['date_internal' => ['field1' => 'value1', 'field2' => 'value2']] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php index 6efd01caee835..3b42c40605458 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFileTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\Filesystem::class, [], [], '', false); $registry = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); $logger = $this->getMock(\Psr\Log\LoggerInterface::class, [], [], '', false); + $serializer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\Serialize\Serializer\Json::class + ); $this->_model = $this->getMockForAbstractClass( \Magento\Catalog\Model\Product\Type\AbstractType::class, [ @@ -46,7 +49,8 @@ protected function setUp() $filesystem, $registry, $logger, - $productRepository + $productRepository, + $serializer ] ); } @@ -186,7 +190,7 @@ public function testPrepareForCart() $this->assertInstanceOf(\Magento\Framework\DataObject::class, $buyRequest); $this->assertEquals($product->getId(), $buyRequest->getProductId()); $this->assertSame($product, $buyRequest->getProduct()); - $this->assertEquals(serialize($requestData), $buyRequest->getValue()); + $this->assertEquals(json_encode($requestData), $buyRequest->getValue()); } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php index 30b300c13b0d4..3e74f6e5ce779 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php @@ -1,6 +1,6 @@ assertTrue((bool)$this->_model->isSaleable()); $this->assertTrue((bool)$this->_model->isAvailable()); $this->assertTrue($this->_model->isInStock()); + } + + /** + * @covers \Magento\Catalog\Model\Product::isSalable + * @covers \Magento\Catalog\Model\Product::isSaleable + * @covers \Magento\Catalog\Model\Product::isAvailable + * @covers \Magento\Catalog\Model\Product::isInStock + */ + public function testIsNotSalableWhenStatusDisabled() + { + $this->_model = $this->productRepository->get('simple'); + $this->_model->setStatus(0); $this->assertFalse((bool)$this->_model->isSalable()); $this->assertFalse((bool)$this->_model->isSaleable()); @@ -476,13 +488,24 @@ public function testValidateUniqueInputAttributeValue() } /** - * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_options.php * @magentoAppIsolation enabled */ public function testGetOptions() { - $this->_model = $this->productRepository->get('simple'); - - $this->assertEquals(4, count($this->_model->getOptions())); + $this->_model = $this->productRepository->get('simple_with_custom_options'); + $options = $this->_model->getOptions(); + $this->assertNotEmpty($options); + $expectedValue = [ + '3-1-select' => 3000.00, + '3-2-select' => 5000.00, + '4-1-radio' => 600.234, + '4-2-radio' => 40000.00 + ]; + foreach ($options as $option) { + foreach ($option->getValues() as $value) { + $this->assertEquals($expectedValue[$value->getSku()], floatval($value->getPrice())); + } + } } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Eav/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Eav/AttributeTest.php index 459aa06d79a39..b3f30485e160b 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Eav/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Eav/AttributeTest.php @@ -1,6 +1,6 @@ processor = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Catalog\Model\Indexer\Product\Price\Processor::class ); + + $this->productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Api\ProductRepositoryInterface::class + ); } /** @@ -100,4 +109,19 @@ public function testAddPriceDataOnSave() $this->assertCount(2, $items); $this->assertEquals(15, $product->getPrice()); } + + /** + * @magentoDataFixture Magento/Catalog/Model/ResourceModel/_files/product_simple.php + * @magentoDbIsolation enabled + */ + public function testGetProductsWithTierPrice() + { + $product = $this->productRepository->get('simple products'); + $items = $this->collection->addIdFilter($product->getId())->addAttributeToSelect('price') + ->load()->addTierPriceData(); + $tierPrices = $items->getFirstItem()->getTierPrices(); + $this->assertCount(3, $tierPrices); + $this->assertEquals(50, $tierPrices[2]->getExtensionAttributes()->getPercentageValue()); + $this->assertEquals(5, $tierPrices[2]->getValue()); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php index ed8f12020a977..f13f3a5df4726 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Product/Indexer/Eav/SourceTest.php @@ -1,6 +1,6 @@ create(\Magento\Catalog\Model\Product::class); $product->isObjectNew(true); $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) - ->setId(2) ->setAttributeSetId(4) ->setWebsiteIds([1]) ->setName('Simple Products') @@ -33,6 +32,12 @@ 'price_qty' => 21, 'price' => 81, ], + [ + 'website_id' => 0, + 'cust_group' => Group::CUST_GROUP_ALL, + 'price_qty' => 30, + 'percentage_value' => 50, + ], ] ) ->setDescription('Description with html tag') diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/url_rewrites.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/url_rewrites.php index a6564ec5db74f..4ce6adf2bf5d7 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/url_rewrites.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/url_rewrites.php @@ -1,6 +1,6 @@ loadArea('adminhtml'); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Webapi/Product/Option/Type/File/ProcessorTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Webapi/Product/Option/Type/File/ProcessorTest.php index 07b3a809b3abe..76596cf063c80 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Webapi/Product/Option/Type/File/ProcessorTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Webapi/Product/Option/Type/File/ProcessorTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + */ + public function testPriceAttributeHasScopeGlobal() + { + foreach (['price', 'cost', 'special_price'] as $attributeCode) { + $attribute = $this->objectManager->get(\Magento\Eav\Model\Config::class)->getAttribute( + 'catalog_product', + $attributeCode + ); + $this->assertTrue($attribute->isScopeGlobal()); + } + } + + /** + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + */ + public function testPriceAttributeHasScopeWebsite() + { + /** @var ReinitableConfigInterface $config */ + $config = $this->objectManager->get( + ReinitableConfigInterface::class + ); + $config->setValue( + \Magento\Store\Model\Store::XML_PATH_PRICE_SCOPE, + \Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + + $eventManager = $this->objectManager->get(\Magento\Framework\Event\ManagerInterface::class); + $eventManager->dispatch( + "admin_system_config_changed_section_catalog", + ['website' => 0, 'store' => 0] + ); + foreach (['price', 'cost', 'special_price'] as $attributeCode) { + $attribute = $this->objectManager->get(\Magento\Eav\Model\Config::class)->getAttribute( + 'catalog_product', + $attributeCode + ); + $this->assertTrue($attribute->isScopeWebsite()); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Pricing/Render/FinalPriceBoxTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Pricing/Render/FinalPriceBoxTest.php new file mode 100644 index 0000000000000..5b03abea2f13e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Pricing/Render/FinalPriceBoxTest.php @@ -0,0 +1,147 @@ +objectManager = Bootstrap::getObjectManager(); + + $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + + $this->appState = $this->objectManager->get(State::class); + $this->appState->setAreaCode(Area::AREA_FRONTEND); + + $this->phtml = $this->objectManager->create(Php::class); + + $this->templateEnginePool = $this->objectManager->get(TemplateEnginePool::class); + + $enginesReflection = new \ReflectionProperty( + $this->templateEnginePool, + 'engines' + ); + $enginesReflection->setAccessible(true); + $enginesReflection->setValue($this->templateEnginePool, ['phtml' => $this->phtml]); + + $this->rendererPool = $this->objectManager->create( + RendererPool::class + ); + + $this->rendererPool->setData( + [ + 'default' => + [ + 'default_amount_render_class' => Amount::class, + 'default_amount_render_template' => 'Magento_Catalog::product/price/amount/default.phtml' + ] + ] + ); + + $this->saleableItem = $this->productRepository->get('tier_prices'); + $this->finalPrice = $this->objectManager->create( + FinalPrice::class, + [ + 'saleableItem' => $this->saleableItem, + 'quantity' => null + ] + ); + + $this->finalPriceBox = $this->objectManager->create( + FinalPriceBox::class, + [ + 'saleableItem' => $this->saleableItem, + 'price' => $this->finalPrice, + 'rendererPool' => $this->rendererPool + ] + ); + + $this->finalPriceBox->setData('price_id', 'test_price_id'); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_has_tier_price_show_as_low_as.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testRenderAmountMinimalProductWithTierPricesShouldShowMinTierPrice() + { + $result = $this->finalPriceBox->renderAmountMinimal(); + $this->assertContains('$5.00', $result); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_different_store_prices.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + */ + public function testProductSetDifferentStorePricesWithoutTierPriceShouldNotShowAsLowAs() + { + $this->assertEmpty($this->finalPriceBox->renderAmountMinimal()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php new file mode 100644 index 0000000000000..d58ca58b433cf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php @@ -0,0 +1,50 @@ +get(\Magento\Framework\Registry::class); + /** @var $store \Magento\Store\Model\Store */ + $store = $objectManager->create(\Magento\Store\Model\Store::class); + $store->load('admin'); + $registry->register('current_store', $store); + $this->object = $objectManager->create(Categories::class); + } + + public function testModifyMeta() + { + $inputMeta = include __DIR__ . '/_files/input_meta_for_categories.php'; + $expectedCategories = include __DIR__ . '/_files/expected_categories.php'; + CacheCleaner::cleanAll(); + $this->assertCategoriesInMeta($expectedCategories, $this->object->modifyMeta($inputMeta)); + // Verify cached data + $this->assertCategoriesInMeta($expectedCategories, $this->object->modifyMeta($inputMeta)); + } + + private function assertCategoriesInMeta(array $expectedCategories, array $meta) + { + $categoriesElement = $meta['product-details']['children']['container_category_ids']['children']['category_ids']; + $this->assertEquals($expectedCategories, $categoriesElement['arguments']['data']['config']['options']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/EavTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/EavTest.php index eeba8d78cead1..afed89a044a68 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/EavTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/EavTest.php @@ -1,6 +1,6 @@ + [ + 'value' => '2', + 'is_active' => '1', + 'label' => 'Default Category', + 'optgroup' => + [ + 0 => + [ + 'value' => '3', + 'is_active' => '1', + 'label' => 'Category 1', + 'optgroup' => + [ + 0 => + [ + 'value' => '4', + 'is_active' => '1', + 'label' => 'Category 1.1', + 'optgroup' => + [ + 0 => + [ + 'value' => '5', + 'is_active' => '1', + 'label' => 'Category 1.1.1', + ], + ], + ], + 1 => + [ + 'value' => '13', + 'is_active' => '1', + 'label' => 'Category 1.2', + ], + ], + ], + 1 => + [ + 'value' => '6', + 'is_active' => '1', + 'label' => 'Category 2', + ], + 2 => + [ + 'value' => '7', + 'is_active' => '1', + 'label' => 'Movable', + ], + 3 => + [ + 'value' => '8', + 'is_active' => '0', + 'label' => 'Inactive', + ], + 4 => + [ + 'value' => '9', + 'is_active' => '1', + 'label' => 'Movable Position 1', + ], + 5 => + [ + 'value' => '10', + 'is_active' => '1', + 'label' => 'Movable Position 2', + ], + 6 => + [ + 'value' => '11', + 'is_active' => '1', + 'label' => 'Movable Position 3', + ], + 7 => + [ + 'value' => '12', + 'is_active' => '1', + 'label' => 'Category 12', + ], + ], + ], +]; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/_files/input_meta_for_categories.php b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/_files/input_meta_for_categories.php new file mode 100644 index 0000000000000..acb5f2c580b06 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/_files/input_meta_for_categories.php @@ -0,0 +1,56 @@ + + [ + 'children' => + ['container_category_ids' => + [ + 'arguments' => + [ + 'data' => + [ + 'config' => + [ + 'formElement' => 'container', + 'componentType' => 'container', + 'breakLine' => false, + 'label' => 'Categories', + 'required' => '0', + 'sortOrder' => 70, + ], + ], + ], + 'children' => + [ + 'category_ids' => + [ + 'arguments' => + [ + 'data' => + [ + 'config' => + [ + 'dataType' => 'text', + 'formElement' => 'input', + 'visible' => '1', + 'required' => '0', + 'notice' => null, + 'default' => null, + 'label' => 'Categories', + 'code' => 'category_ids', + 'source' => 'product-details', + 'scopeLabel' => '[GLOBAL]', + 'globalScope' => true, + 'sortOrder' => 70, + 'componentType' => 'field', + ], + ], + ], + ], + ], + ]]]]; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/WidgetTest.php b/dev/tests/integration/testsuite/Magento/Catalog/WidgetTest.php index d695fcb6bf653..c915e9809174a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/WidgetTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/WidgetTest.php @@ -1,6 +1,6 @@ get(AttributeSetInterfaceFactory::class); +$attributeGroupFactory = $objectManager->get(AttributeGroupInterfaceFactory::class); +/** @var DataObjectHelper $dataObjectHelper */ +$dataObjectHelper = $objectManager->get(DataObjectHelper::class); +/** @var AttributeGroupRepositoryInterface $attributeGroupRepository */ +$attributeGroupRepository = $objectManager->get(AttributeGroupRepositoryInterface::class); +/** @var AttributeSetRepositoryInterface $attributeSetRepository */ +$attributeSetRepository = $objectManager->get(AttributeSetRepositoryInterface::class); + +/** @var AttributeSetInterface $attributeSet */ +$attributeSet = $attributeSetFactory->create(); +$entityTypeId = $objectManager->create(Type::class)->loadByCode('catalog_product')->getId(); +$dataObjectHelper->populateWithArray( + $attributeSet, + [ + 'attribute_set_name' => 'attribute_set_test', + 'entity_type_id' => $entityTypeId, + ], + AttributeSetInterface::class +); +$attributeSetRepository->save($attributeSet); + +/** @var AttributeGroupInterface $attributeGroup */ +$attributeGroup = $attributeGroupFactory->create(); +$dataObjectHelper->populateWithArray( + $attributeGroup, + [ + 'attribute_set_id' => $attributeSet->getAttributeSetId(), + 'attribute_group_name' => 'attribute-group-name', + 'default_id' => 1, + ], + AttributeGroupInterface::class +); +$attributeGroupRepository->save($attributeGroup); + +// during renaming group code is not changed +$attributeGroup->setAttributeGroupName('attribute-group-renamed'); +$attributeGroupRepository->save($attributeGroup); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php index ac15b246910e3..6cf3f84a0b765 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php @@ -1,6 +1,6 @@ create( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class +); + +if (!$attribute->loadByCode(4, 'dropdown_attribute')->getId()) { + /** @var $installer \Magento\Catalog\Setup\CategorySetup */ + $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Setup\CategorySetup::class + ); + + $attribute->setData( + [ + 'attribute_code' => 'dropdown_attribute', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 0, + 'is_user_defined' => 1, + 'frontend_input' => 'select', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Drop-Down Attribute'], + 'backend_type' => 'varchar', + 'backend_model' => \Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend::class, + 'option' => [ + 'value' => [ + 'option_1' => ['Option 1'], + 'option_2' => ['Option 2'], + 'option_3' => ['Option 3'], + ], + 'order' => [ + 'option_1' => 1, + 'option_2' => 2, + 'option_3' => 3, + ], + ], + ] + ); + $attribute->save(); + + /* Assign attribute to attribute set */ + $installer->addAttributeToGroup('catalog_product', 'Default', 'Attributes', $attribute->getId()); +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/empty_attribute_group.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/empty_attribute_group.php index 0fa389aff6de7..718a6c9f30dd8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/empty_attribute_group.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/empty_attribute_group.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/filterable_attributes.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/filterable_attributes.php index 55f83b3bea653..e444c26a79fdb 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/filterable_attributes.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/filterable_attributes.php @@ -1,6 +1,6 @@ create( @@ -40,7 +39,7 @@ 'option_1' => ['Option 1'], 'option_2' => ['Option 2'], 'option_3' => ['Option 3'], - 'option_4' => ['Option 4 "!@#$%^&*'], + 'option_4' => ['Option 4 "!@#$%^&*'] ], 'order' => [ 'option_1' => 1, diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute_rollback.php new file mode 100644 index 0000000000000..5cb4463eb48d5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute_rollback.php @@ -0,0 +1,18 @@ +get('Magento\Framework\Registry'); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Catalog\Model\ResourceModel\Eav\Attribute' +); +$attribute->load('multiselect_attribute', 'attribute_code'); +$attribute->delete(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute_with_incorrect_values.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute_with_incorrect_values.php new file mode 100644 index 0000000000000..3342c04da625c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/multiselect_attribute_with_incorrect_values.php @@ -0,0 +1,55 @@ +create( + \Magento\Catalog\Setup\CategorySetup::class +); +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class +); +$attribute->setData( + [ + 'attribute_code' => 'multiselect_attribute', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'multiselect', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Multiselect Attribute'], + 'backend_type' => 'varchar', + 'backend_model' => \Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend::class, + 'option' => [ + 'value' => [ + 'option_1' => ['Opt|,=ion 1'], + 'option_2' => ['Opt||,ion 2'], + 'option_3' => ['Option 3 "!@#$%^&*, "|"'] + ], + 'order' => [ + 'option_1' => 1, + 'option_2' => 2, + 'option_3' => 3, + ], + ], + ] +); +$attribute->save(); + +/* Assign attribute to attribute set */ +$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/order_item_with_product_and_custom_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/order_item_with_product_and_custom_options.php index 4fb6a9f76dcae..9583df1222ffe 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/order_item_with_product_and_custom_options.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/order_item_with_product_and_custom_options.php @@ -1,6 +1,6 @@ create(IndexerRegistry::class); +$indexer = $indexerRegistry->get('catalogsearch_fulltext'); + +$indexer->reindexAll(); + +/** @var $product Product */ +$product = $objectManager->create(Product::class); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('tier_prices') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with html tag') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); + +$product->setStoreId($store->getId()); +$product->setPrice(15); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices_rollback.php new file mode 100644 index 0000000000000..f7395f28e0950 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_different_store_prices_rollback.php @@ -0,0 +1,26 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ProductRepository::class +); +try { + $product = $repository->get('tier_prices'); + $product->delete(); +} catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Entity already deleted +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +require __DIR__ . '/../../Store/_files/core_fixturestore_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices_rollback.php index 0146925a00ad0..7b3cd53a4c244 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices_rollback.php @@ -1,6 +1,6 @@ reinitialize(); + +/** @var \Magento\TestFramework\ObjectManager $objectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +$tierPrices = []; +/** @var \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory */ +$tierPriceFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory::class); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 2, + 'value' => 8 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 5, + 'value' => 5 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 3, + 'value' => 5 + ] + ] +); + +/** @var $tpExtensionAttributes */ +$tpExtensionAttributesFactory = $objectManager->create(ProductTierPriceExtensionFactory::class); +$tpExtensionAttributes = $tpExtensionAttributesFactory->create()->setPercentageValue(50); + +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 10 + ] + ] +)->setExtensionAttributes($tpExtensionAttributes); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('tier_prices') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setTierPrices($tierPrices) + ->setDescription('Description with html tag') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepositoryFactory */ +$productRepositoryFactory = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$productRepositoryFactory->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as_rollback.php new file mode 100644 index 0000000000000..02726154857f7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_has_tier_price_show_as_low_as_rollback.php @@ -0,0 +1,24 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ProductRepository::class +); +try { + $product = $repository->get('tier_prices'); + $product->delete(); +} catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Entity already deleted +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php index 2561be9a60d43..85e50993cd565 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php @@ -1,6 +1,6 @@ reinitialize(); /** @var \Magento\TestFramework\ObjectManager $objectManager */ @@ -12,6 +14,92 @@ /** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */ $categoryLinkManagement = $objectManager->create(\Magento\Catalog\Api\CategoryLinkManagementInterface::class); +$tierPrices = []; +/** @var \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory */ +$tierPriceFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory::class); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 2, + 'value' => 8 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 5, + 'value' => 5 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 3, + 'value' => 5 + ] + ] +); +/** @var $tpExtensionAttributes */ +$tpExtensionAttributesFactory = $objectManager->create(ProductTierPriceExtensionFactory::class); +$tpExtensionAttributes = $tpExtensionAttributesFactory->create()->setPercentageValue(50); + +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 10 + ] + ] +)->setExtensionAttributes($tpExtensionAttributes); + +$tierPrices = []; +/** @var \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory $tierPriceFactory */ +$tierPriceFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory::class); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 2, + 'value' => 8 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, + 'qty' => 5, + 'value' => 5 + ] + ] +); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 3, + 'value' => 5 + ] + ] +); +/** @var $tpExtensionAttributes */ +$tpExtensionAttributesFactory = $objectManager->create(ProductTierPriceExtensionFactory::class); +$tpExtensionAttributes = $tpExtensionAttributesFactory->create()->setPercentageValue(50); + +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 10 + ] + ] +)->setExtensionAttributes($tpExtensionAttributes); + /** @var $product \Magento\Catalog\Model\Product */ $product = $objectManager->create(\Magento\Catalog\Model\Product::class); $product->isObjectNew(true); @@ -25,28 +113,7 @@ ->setWeight(1) ->setShortDescription("Short description") ->setTaxClassId(0) - ->setTierPrice( - [ - [ - 'website_id' => 0, - 'cust_group' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, - 'price_qty' => 2, - 'price' => 8, - ], - [ - 'website_id' => 0, - 'cust_group' => \Magento\Customer\Model\Group::CUST_GROUP_ALL, - 'price_qty' => 5, - 'price' => 5, - ], - [ - 'website_id' => 0, - 'cust_group' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, - 'price_qty' => 3, - 'price' => 5, - ], - ] - ) + ->setTierPrices($tierPrices) ->setDescription('Description with html tag') ->setMetaTitle('meta title') ->setMetaKeyword('meta keyword') @@ -93,14 +160,14 @@ 'sort_order' => 0, 'values' => [ [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 1', 'price' => 3, 'price_type' => 'fixed', 'sku' => '3-1-select', ], [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 2', 'price' => 3, 'price_type' => 'fixed', @@ -116,14 +183,14 @@ 'sort_order' => 0, 'values' => [ [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 1', 'price' => 3, 'price_type' => 'fixed', 'sku' => '4-1-radio', ], [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 2', 'price' => 3, 'price_type' => 'fixed', diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_duplicated.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_duplicated.php index 59cdd76b9abfb..9b004cc179fcd 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_duplicated.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_duplicated.php @@ -1,6 +1,6 @@ 0, 'values' => [ [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 1', 'price' => 3, 'price_type' => 'fixed', 'sku' => '3-1-select', ], [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 2', 'price' => 3, 'price_type' => 'fixed', @@ -121,14 +121,14 @@ 'sort_order' => 0, 'values' => [ [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 1', 'price' => 3, 'price_type' => 'fixed', 'sku' => '4-1-radio', ], [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 2', 'price' => 3, 'price_type' => 'fixed', diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php new file mode 100644 index 0000000000000..2ff89bf05579c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options.php @@ -0,0 +1,114 @@ +reinitialize(); + +/** @var \Magento\TestFramework\ObjectManager $objectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */ +$categoryLinkManagement = $objectManager->create(\Magento\Catalog\Api\CategoryLinkManagementInterface::class); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->isObjectNew(true); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('simple_with_custom_options') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with html tag') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + )->setCanSaveCustomOptions(true) + ->setHasOptions(true); + +$oldOptions = [ + [ + 'previous_group' => 'select', + 'title' => 'Test Select', + 'type' => 'drop_down', + 'is_require' => 1, + 'sort_order' => 0, + 'values' => [ + [ + 'option_type_id' => null, + 'title' => 'Option 1', + 'price' => '3,000.00', + 'price_type' => 'fixed', + 'sku' => '3-1-select', + ], + [ + 'option_type_id' => null, + 'title' => 'Option 2', + 'price' => '5,000.00', + 'price_type' => 'fixed', + 'sku' => '3-2-select', + ], + ] + ], + [ + 'previous_group' => 'select', + 'title' => 'Test Radio', + 'type' => 'radio', + 'is_require' => 1, + 'sort_order' => 0, + 'values' => [ + [ + 'option_type_id' => null, + 'title' => 'Option 1', + 'price' => '600.234', + 'price_type' => 'fixed', + 'sku' => '4-1-radio', + ], + [ + 'option_type_id' => null, + 'title' => 'Option 2', + 'price' => '40,000.00', + 'price_type' => 'fixed', + 'sku' => '4-2-radio', + ], + ] + ] +]; + +$options = []; + +/** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory $customOptionFactory */ +$customOptionFactory = $objectManager->create(\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory::class); + +foreach ($oldOptions as $option) { + /** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterface $option */ + $option = $customOptionFactory->create(['data' => $option]); + $option->setProductSku($product->getSku()); + + $options[] = $option; +} + +$product->setOptions($options); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepositoryFactory */ +$productRepositoryFactory = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$productRepositoryFactory->save($product); + +$categoryLinkManagement->assignProductToCategories( + $product->getSku(), + [2] +); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options_rollback.php new file mode 100644 index 0000000000000..dc35cf6b70ce8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_options_rollback.php @@ -0,0 +1,26 @@ +getInstance()->reinitialize(); + +/** @var \Magento\Framework\Registry $registry */ +$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); +try { + $product = $productRepository->get('simple_with_custom_options', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_url_key.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_url_key.php index 31c4d50843675..563d4d72c9954 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_url_key.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_url_key.php @@ -1,6 +1,6 @@ create(\Magento\Catalog\Setup\CategorySetup::class); +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class); +$attribute->setData( + [ + 'attribute_code' => 'text_attribute', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'textarea', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Text Attribute'], + 'backend_type' => 'text', + ] +); +$attribute->save(); +/* Assign attribute to attribute set */ +$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php index 95289151c48ac..714067f10593b 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php @@ -1,6 +1,6 @@ get(Magento\Store\Model\Website::class); -$website->load('second_website', 'code'); -if (!$website->getId()) { - $website->setData( - [ - 'code' => 'second_website', - 'name' => 'Test Website', - ] - ); +$website->setData( + [ + 'code' => 'second_website', + 'name' => 'Test Website', + ] +); - $website->save(); -} +$website->save(); + +$objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->reinitStores(); /** @var $product \Magento\Catalog\Model\Product */ $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->create(ProductInterface::class); $product ->setTypeId('simple') - ->setId(1) ->setAttributeSetId(4) ->setWebsiteIds([1, $website->getId()]) ->setName('Simple Product') diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_two_websites_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_two_websites_rollback.php new file mode 100644 index 0000000000000..e6de8a3935c5c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_two_websites_rollback.php @@ -0,0 +1,35 @@ +get(\Magento\Framework\Registry::class); +$registry->unregister("isSecureArea"); +$registry->register("isSecureArea", true); + +/** @var Magento\Store\Model\Website $website */ +$website = $objectManager->create(\Magento\Store\Model\Website::class); +$website->load('second_website'); +$website->delete(); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +try { + $firstProduct = $productRepository->get('unique-simple-azaza'); + $firstProduct->delete(); +} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +$objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->reinitStores(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php index 6c4373cc723a0..b3d8bc390a7be 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_without_options.php @@ -1,6 +1,6 @@ create( \Magento\Catalog\Setup\CategorySetup::class @@ -19,51 +25,30 @@ /** @var $product \Magento\Catalog\Model\Product */ $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); -$product->setTypeId( - \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE -)->setId( - $optionIds[0] * 10 -)->setAttributeSetId( - $installer->getAttributeSetId('catalog_product', 'Default') -)->setWebsiteIds( - [1] -)->setName( - 'With Multiselect 1' -)->setSku( - 'simple_ms_1' -)->setPrice( - 10 -)->setVisibility( - \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH -)->setMultiselectAttribute( - [$optionIds[0]] -)->setStatus( - \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED -)->setStockData( - ['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1] -)->save(); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId($optionIds[0] * 10) + ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default')) + ->setWebsiteIds([1]) + ->setName('With Multiselect 1') + ->setSku('simple_ms_1') + ->setPrice(10) + ->setDescription('Hello " &" Bring the water bottle when you can!') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setMultiselectAttribute([$optionIds[0]]) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->save(); $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); -$product->setTypeId( - \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE -)->setId( - $optionIds[1] * 10 -)->setAttributeSetId( - $installer->getAttributeSetId('catalog_product', 'Default') -)->setWebsiteIds( - [1] -)->setName( - 'With Multiselect 2' -)->setSku( - 'simple_ms_2' -)->setPrice( - 10 -)->setVisibility( - \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH -)->setMultiselectAttribute( - [$optionIds[1], $optionIds[2], $optionIds[3]] -)->setStatus( - \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED -)->setStockData( - ['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1] -)->save(); +$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId($optionIds[1] * 10) + ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default')) + ->setWebsiteIds([1]) + ->setName('With Multiselect 2') + ->setSku('simple_ms_2') + ->setPrice(10) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setMultiselectAttribute([$optionIds[1], $optionIds[2], $optionIds[3]]) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_multiselect_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_multiselect_attribute_rollback.php new file mode 100644 index 0000000000000..8f595cb6fb197 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_multiselect_attribute_rollback.php @@ -0,0 +1,23 @@ +get('Magento\Framework\Registry'); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var $productCollection \Magento\Catalog\Model\ResourceModel\Product */ +$productCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create('Magento\Catalog\Model\Product') + ->getCollection(); + +foreach ($productCollection as $product) { + $product->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_unique_input_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_unique_input_attribute.php index 4f16ce6baa603..d07181528316d 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_unique_input_attribute.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_unique_input_attribute.php @@ -1,6 +1,6 @@ save(); } + +$objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->reinitStores(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/second_website_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_website_rollback.php new file mode 100644 index 0000000000000..e431d527963bb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/second_website_rollback.php @@ -0,0 +1,22 @@ +get('Magento\Framework\Registry'); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$website = $objectManager->get(Magento\Store\Model\Website::class); +$website->load('test_website', 'code'); + +if ($website->getId()) { + $website->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +$objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->reinitStores(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/text_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/text_attribute_rollback.php new file mode 100644 index 0000000000000..48f7bcdab1452 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/text_attribute_rollback.php @@ -0,0 +1,18 @@ +get('Magento\Framework\Registry'); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + 'Magento\Catalog\Model\ResourceModel\Eav\Attribute' +); +$attribute->load('text_attribute', 'attribute_code'); +$attribute->delete(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/unique_input_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/unique_input_attribute.php index a45b4f129486e..837f089aac1a5 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/unique_input_attribute.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/unique_input_attribute.php @@ -2,7 +2,7 @@ /** * "Input" fixture of product EAV attribute. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites.php index 61501a6a5740b..58b06100c4fb3 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites.php @@ -1,6 +1,6 @@ loadArea('adminhtml'); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites_invalid.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites_invalid.php index fe6c673daba3e..1dd526e4bbe0c 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites_invalid.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/url_rewrites_invalid.php @@ -1,6 +1,6 @@ productResource = $this->objectManager->create( \Magento\Catalog\Model\ResourceModel\Product::class ); + \Magento\CatalogImportExport\Model\Import\Product\Type\AbstractType::$commonAttributesCache = []; } protected function tearDown() diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php index 67e866cf18807..d96c02c3e9ae7 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php @@ -1,12 +1,14 @@ assertContains('Option 4 ""!@#$%^&*', $exportData); $this->assertContains('test_option_code_2', $exportData); $this->assertContains('max_characters=10', $exportData); + $this->assertContains('text_attribute=!@#$%^&*()_+1234567890-=|\\:;""\'<,>.?/', $exportData); + $occurrencesCount = substr_count($exportData, 'Hello "" &"" Bring the water bottle when you can!'); + $this->assertEquals(1, $occurrencesCount); + } + + /** + * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_data_special_chars.php + * @magentoDbIsolationEnabled + */ + public function testExportSpecialChars() + { + $this->model->setWriter( + $this->objectManager->create( + \Magento\ImportExport\Model\Export\Adapter\Csv::class + ) + ); + $exportData = $this->model->export(); + $this->assertContains('simple ""1""', $exportData); } /** * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_with_product_links_data.php + * @magentoDbIsolationEnabled */ public function testExportWithProductLinks() { @@ -100,7 +122,9 @@ public function testExportWithProductLinks() /** * Verify that all stock item attribute values are exported (aren't equal to empty string) - * + * + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled * @covers \Magento\CatalogImportExport\Model\Export\Product::export * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_data.php */ @@ -162,7 +186,7 @@ public function verifyRow(array $rowData) /** * Verifies if exception processing works properly - * + * @magentoDbIsolation enabled * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_data.php */ public function testExceptionInGetExportData() @@ -205,4 +229,55 @@ public function testExceptionInGetExportData() $data = $model->setWriter($exportAdapter)->export(); $this->assertEmpty($data); } + + /** + * Verify if fields wrapping works correct when "Fields Enclosure" option enabled + * + * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_data.php + */ + public function testExportWithFieldsEnclosure() + { + $this->model->setParameters([ + \Magento\ImportExport\Model\Export::FIELDS_ENCLOSURE => 1 + ]); + + $this->model->setWriter( + $this->objectManager->create( + \Magento\ImportExport\Model\Export\Adapter\Csv::class + ) + ); + $exportData = $this->model->export(); + + $this->assertContains('""Option 2""', $exportData); + $this->assertContains('""Option 3""', $exportData); + $this->assertContains('""Option 4 """"!@#$%^&*""', $exportData); + $this->assertContains('text_attribute=""!@#$%^&*()_+1234567890-=|\:;""""\'<,>.?/', $exportData); + } + + /** + * Verify that "category ids" filter correctly applies to export result + * + * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_with_categories.php + */ + public function testCategoryIdsFilter() + { + $this->model->setWriter( + $this->objectManager->create( + \Magento\ImportExport\Model\Export\Adapter\Csv::class + ) + ); + + $this->model->setParameters([ + \Magento\ImportExport\Model\Export::FILTER_ELEMENT_GROUP => [ + 'category_ids' => '2,13' + ] + ]); + + $exportData = $this->model->export(); + + $this->assertContains('Simple Product', $exportData); + $this->assertContains('Simple Product Three', $exportData); + $this->assertNotContains('Simple Product Two', $exportData); + $this->assertNotContains('Simple Product Not Visible On Storefront', $exportData); + } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractTest.php index e935c4b653a31..48e8fee72ef1d 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/Product/Type/AbstractTest.php @@ -1,6 +1,6 @@ load($productBeforeImport->getId()); $this->assertEquals( - @strtotime($row['news_from_date']), + @strtotime(date('m/d/Y', @strtotime($row['news_from_date']))), @strtotime($productAfterImport->getNewsFromDate()) ); + $this->assertEquals( + @strtotime($row['news_to_date']), + @strtotime($productAfterImport->getNewsToDate()) + ); unset($productAfterImport); } unset($productsBeforeImport, $product); @@ -557,57 +564,14 @@ protected function getOptionValues(\Magento\Catalog\Model\Product\Option $option /** * @magentoDataIsolation enabled * @magentoDataFixture mediaImportImageFixture - * + * @magentoAppIsolation enabled * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testSaveMediaImage() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Framework\Filesystem::class); - $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); - - $source = $this->objectManager->create( - \Magento\ImportExport\Model\Import\Source\Csv::class, - [ - 'file' => __DIR__ . '/_files/import_media.csv', - 'directory' => $directory - ] - ); - $this->_model->setParameters( - [ - 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, - 'entity' => 'catalog_product', - 'import_images_file_dir' => 'pub/media/import' - ] - ); - $appParams = \Magento\TestFramework\Helper\Bootstrap::getInstance() - ->getBootstrap() - ->getApplication() - ->getInitParams()[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]; - $uploader = $this->_model->getUploader(); - - $destDir = $directory->getRelativePath($appParams[DirectoryList::MEDIA][DirectoryList::PATH] . '/catalog/product'); - $tmpDir = $directory->getRelativePath($appParams[DirectoryList::MEDIA][DirectoryList::PATH] . '/import'); - - $directory->create($destDir); - $this->assertTrue($uploader->setDestDir($destDir)); - $this->assertTrue($uploader->setTmpDir($tmpDir)); - $errors = $this->_model->setSource( - $source - )->validateData(); - - $this->assertTrue($errors->getErrorsCount() == 0); - $this->_model->importData(); - $this->assertTrue($this->_model->getErrorAggregator()->getErrorsCount() == 0); + $this->importDataForMediaTest('import_media.csv'); + $product = $this->getProductBySku('simple_new'); - $resource = $objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class); - $productId = $resource->getIdBySku('simple_new'); - - $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Product::class - ); - $product->load($productId); $this->assertEquals('/m/a/magento_image.jpg', $product->getData('swatch_image')); $gallery = $product->getMediaGalleryImages(); $this->assertInstanceOf(\Magento\Framework\Data\Collection::class, $gallery); @@ -619,6 +583,25 @@ public function testSaveMediaImage() $this->assertEquals('Image Label', $item->getLabel()); } + /** + * Test that image labels updates after import + * + * @magentoDataFixture mediaImportImageFixture + * @magentoDataFixture Magento/Catalog/_files/product_with_image.php + */ + public function testUpdateImageLabel() + { + $this->importDataForMediaTest('import_media_update_label.csv'); + $product = $this->getProductBySku('simple'); + + $gallery = $product->getMediaGalleryImages(); + $items = $gallery->getItems(); + $this->assertCount(1, $items); + $item = array_pop($items); + $this->assertInstanceOf(\Magento\Framework\DataObject::class, $item); + $this->assertEquals('Updated Image Label', $item->getLabel()); + } + /** * Copy a fixture image into media import directory */ @@ -732,6 +715,7 @@ public function testInvalidSkuLink() /** * @magentoDataFixture Magento/Catalog/_files/products_with_multiselect_attribute.php * @magentoAppIsolation enabled + * @magentoDbIsolation enabled */ public function testValidateInvalidMultiselectValues() { @@ -1048,9 +1032,9 @@ protected function loadCategoryByName($categoryName) * @magentoAppIsolation enabled * @dataProvider validateUrlKeysDataProvider * @param $importFile string - * @param $errorsCount int + * @param $expectedErrors array */ - public function testValidateUrlKeys($importFile, $errorsCount) + public function testValidateUrlKeys($importFile, $expectedErrors) { $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Framework\Filesystem::class @@ -1064,19 +1048,16 @@ public function testValidateUrlKeys($importFile, $errorsCount) 'directory' => $directory ] ); + /** @var \Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface $errors */ $errors = $this->_model->setParameters( ['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, 'entity' => 'catalog_product'] )->setSource( $source )->validateData(); - - $this->assertTrue($errors->getErrorsCount() == $errorsCount); - if ($errorsCount >= 1) { - $this->assertEquals( - "Specified URL key already exists", - $errors->getErrorByRowNumber(1)[0]->getErrorMessage() - ); - } + $this->assertEquals( + $expectedErrors[RowValidatorInterface::ERROR_DUPLICATE_URL_KEY], + count($errors->getErrorsByCode([RowValidatorInterface::ERROR_DUPLICATE_URL_KEY])) + ); } /** @@ -1085,9 +1066,24 @@ public function testValidateUrlKeys($importFile, $errorsCount) public function validateUrlKeysDataProvider() { return [ - ['products_to_check_valid_url_keys.csv', 0], - ['products_to_check_duplicated_url_keys.csv', 2], - ['products_to_check_duplicated_names.csv' , 1] + [ + 'products_to_check_valid_url_keys.csv', + [ + RowValidatorInterface::ERROR_DUPLICATE_URL_KEY => 0 + ] + ], + [ + 'products_to_check_duplicated_url_keys.csv', + [ + RowValidatorInterface::ERROR_DUPLICATE_URL_KEY => 2 + ] + ], + [ + 'products_to_check_duplicated_names.csv' , + [ + RowValidatorInterface::ERROR_DUPLICATE_URL_KEY => 1 + ] + ] ]; } @@ -1195,7 +1191,6 @@ public function testProductWithLinks() */ public function testExistingProductWithUrlKeys() { - $this->markTestSkipped('Test must be unskiped after implementation MAGETWO-48871'); $products = [ 'simple1' => 'url-key1', 'simple2' => 'url-key2', @@ -1229,6 +1224,42 @@ public function testExistingProductWithUrlKeys() } } + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_url_key.php + * @magentoAppIsolation enabled + */ + public function testImportWithoutUrlKeys() + { + $products = [ + 'simple1' => 'simple-1', + 'simple2' => 'simple-2', + 'simple3' => 'simple-3' + ]; + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/products_to_import_without_url_keys.csv', + 'directory' => $directory + ] + ); + + $errors = $this->_model->setParameters( + ['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, 'entity' => 'catalog_product'] + ) + ->setSource($source) + ->validateData(); + + $this->assertTrue($errors->getErrorsCount() == 0); + $this->_model->importData(); + + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + foreach ($products as $productSku => $productUrlKey) { + $this->assertEquals($productUrlKey, $productRepository->get($productSku)->getUrlKey()); + } + } + /** * @magentoAppIsolation enabled */ @@ -1268,4 +1299,284 @@ public function testProductWithUseConfigSettings() $this->assertEquals($manageStockUseConfig, $stockItem->getUseConfigManageStock()); } } + + /** + * @magentoDataFixture Magento/Store/_files/website.php + * @magentoDataFixture Magento/Store/_files/core_fixturestore.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testProductWithMultipleStoresInDifferentBunches() + { + $products = [ + 'simple1', + 'simple2', + 'simple3' + ]; + + $importExportData = $this->getMockBuilder(\Magento\ImportExport\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + $importExportData->expects($this->atLeastOnce()) + ->method('getBunchSize') + ->willReturn(1); + $this->_model = $this->objectManager->create( + \Magento\CatalogImportExport\Model\Import\Product::class, + ['importExportData' => $importExportData] + ); + + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/products_to_import_with_multiple_store.csv', + 'directory' => $directory + ] + ); + $errors = $this->_model->setParameters( + ['behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, 'entity' => 'catalog_product'] + )->setSource( + $source + )->validateData(); + + $this->assertTrue($errors->getErrorsCount() == 0); + + $this->_model->importData(); + $productCollection = $this->objectManager + ->create(\Magento\Catalog\Model\ResourceModel\Product\Collection::class); + $this->assertCount(3, $productCollection->getItems()); + $actualProductSkus = array_map( + function(ProductInterface $item) { + return $item->getSku(); + }, + $productCollection->getItems() + ); + $this->assertEquals( + $products, + array_values($actualProductSkus) + ); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/multiselect_attribute_with_incorrect_values.php + * @magentoDataFixture Magento/Catalog/_files/product_text_attribute.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ + public function testProductWithWrappedAdditionalAttributes() + { + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/products_to_import_with_additional_attributes.csv', + 'directory' => $directory + ] + ); + $errors = $this->_model->setParameters( + [ + 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, + 'entity' => 'catalog_product', + \Magento\ImportExport\Model\Import::FIELDS_ENCLOSURE => 1 + ] + )->setSource( + $source + )->validateData(); + + $this->assertTrue($errors->getErrorsCount() == 0); + + $this->_model->importData(); + + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Api\ProductRepositoryInterface::class + ); + + /** @var \Magento\Eav\Api\AttributeOptionManagementInterface $multiselectOptions */ + $multiselectOptions = $this->objectManager->get(\Magento\Eav\Api\AttributeOptionManagementInterface::class) + ->getItems(\Magento\Catalog\Model\Product::ENTITY, 'multiselect_attribute'); + + $product1 = $productRepository->get('simple1'); + $this->assertEquals('\'", =|', $product1->getData('text_attribute')); + $this->assertEquals(implode(',', [$multiselectOptions[3]->getValue(), $multiselectOptions[2]->getValue()]), + $product1->getData('multiselect_attribute')); + + $product2 = $productRepository->get('simple2'); + $this->assertEquals('', $product2->getData('text_attribute')); + $this->assertEquals(implode(',', [$multiselectOptions[1]->getValue(), $multiselectOptions[2]->getValue()]), + $product2->getData('multiselect_attribute')); + } + + /** + * Import and check data from file + * + * @param string $fileName + */ + private function importDataForMediaTest($fileName) + { + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/' . $fileName, + 'directory' => $directory + ] + ); + $this->_model->setParameters( + [ + 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, + 'entity' => 'catalog_product', + 'import_images_file_dir' => 'pub/media/import' + ] + ); + $appParams = \Magento\TestFramework\Helper\Bootstrap::getInstance() + ->getBootstrap() + ->getApplication() + ->getInitParams()[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS]; + $uploader = $this->_model->getUploader(); + + $mediaPath = $appParams[DirectoryList::MEDIA][DirectoryList::PATH]; + $destDir = $directory->getRelativePath($mediaPath . '/catalog/product'); + $tmpDir = $directory->getRelativePath($mediaPath . '/import'); + + $directory->create($destDir); + $this->assertTrue($uploader->setDestDir($destDir)); + $this->assertTrue($uploader->setTmpDir($tmpDir)); + $errors = $this->_model->setSource( + $source + )->validateData(); + $this->assertTrue($errors->getErrorsCount() == 0); + + $this->_model->importData(); + $this->assertTrue($this->_model->getErrorAggregator()->getErrorsCount() == 0); + } + + /** + * Load product by given product sku + * + * @param string $sku + * @return \Magento\Catalog\Model\Product + */ + private function getProductBySku($sku) + { + $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class); + $productId = $resource->getIdBySku($sku); + $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class); + $product->load($productId); + + return $product; + } + + /** + * @param array $row + * @param string|null $behavior + * @param bool $expectedResult + * @magentoAppArea adminhtml + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Catalog/Model/ResourceModel/_files/product_simple.php + * @dataProvider validateRowDataProvider + */ + public function testValidateRow(array $row, $behavior, $expectedResult) + { + $this->_model->setParameters(['behavior' => $behavior, 'entity' => 'catalog_product']); + $this->assertSame($expectedResult, $this->_model->validateRow($row, 1)); + } + + /** + * @return array + */ + public function validateRowDataProvider() + { + return [ + [ + 'row' => ['sku' => 'simple products'], + 'behavior' => null, + 'expectedResult' => true, + ], + [ + 'row' => ['sku' => 'simple products absent'], + 'behavior' => null, + 'expectedResult' => false, + ], + [ + 'row' => [ + 'sku' => 'simple products absent', + 'name' => 'Test', + 'product_type' => 'simple', + '_attribute_set' => 'Default', + 'price' => 10.20, + ], + 'behavior' => null, + 'expectedResult' => true, + ], + [ + 'row' => ['sku' => 'simple products'], + 'behavior' => Import::BEHAVIOR_ADD_UPDATE, + 'expectedResult' => true, + ], + [ + 'row' => ['sku' => 'simple products absent'], + 'behavior' => Import::BEHAVIOR_ADD_UPDATE, + 'expectedResult' => false, + ], + [ + 'row' => [ + 'sku' => 'simple products absent', + 'name' => 'Test', + 'product_type' => 'simple', + '_attribute_set' => 'Default', + 'price' => 10.20, + ], + 'behavior' => Import::BEHAVIOR_ADD_UPDATE, + 'expectedResult' => true, + ], + [ + 'row' => ['sku' => 'simple products'], + 'behavior' => Import::BEHAVIOR_DELETE, + 'expectedResult' => true, + ], + [ + 'row' => ['sku' => 'simple products absent'], + 'behavior' => Import::BEHAVIOR_DELETE, + 'expectedResult' => false, + ], + [ + 'row' => ['sku' => 'simple products'], + 'behavior' => Import::BEHAVIOR_REPLACE, + 'expectedResult' => false, + ], + [ + 'row' => ['sku' => 'simple products absent'], + 'behavior' => Import::BEHAVIOR_REPLACE, + 'expectedResult' => false, + ], + [ + 'row' => [ + 'sku' => 'simple products absent', + 'name' => 'Test', + 'product_type' => 'simple', + '_attribute_set' => 'Default', + 'price' => 10.20, + ], + 'behavior' => Import::BEHAVIOR_REPLACE, + 'expectedResult' => false, + ], + [ + 'row' => [ + 'sku' => 'simple products', + 'name' => 'Test', + 'product_type' => 'simple', + '_attribute_set' => 'Default', + 'price' => 10.20, + ], + 'behavior' => Import::BEHAVIOR_REPLACE, + 'expectedResult' => true, + ], + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_update_label.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_update_label.csv new file mode 100644 index 0000000000000..4e62e28af7ff3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_update_label.csv @@ -0,0 +1,2 @@ +sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus +simple,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,magento_image.jpg,,magento_image.jpg,,magento_image.jpg,,magento_image.jpg,,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,magento_image.jpg,Updated Image Label,,,,,,,, diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image.php index 16c76b2e1b32d..ca4721a5b4890 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/media_import_image.php @@ -1,6 +1,6 @@ reinitialize(); - +/** Create category */ require dirname(dirname(__DIR__)) . '/Catalog/_files/category.php'; +/** Create fixture store */ require dirname(dirname(__DIR__)) . '/Store/_files/second_store.php'; +/** Create product with multiselect attribute and values */ require dirname(dirname(__DIR__)) . '/Catalog/_files/products_with_multiselect_attribute.php'; +/** Create dummy text attribute */ +require dirname(dirname(__DIR__)) . '/Catalog/_files/product_text_attribute.php'; $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/** @var \Magento\Catalog\Model\Product $productModel */ $productModel = $objectManager->create(\Magento\Catalog\Model\Product::class); $customOptions = [ [ - 'id' => 'test_option_code_1', - 'option_id' => '0', + 'option_id' => null, 'sort_order' => '0', 'title' => 'Option 1', 'type' => 'drop_down', 'is_require' => 1, 'values' => [ - 1 => ['option_type_id' => -1, 'title' => 'Option 1 & Value 1"', 'price' => '1.00', 'price_type' => 'fixed'], - 2 => ['option_type_id' => -1, 'title' => 'Option 1 & Value 2"', 'price' => '2.00', 'price_type' => 'fixed'], - 3 => ['option_type_id' => -1, 'title' => 'Option 1 & Value 3"', 'price' => '3.00', 'price_type' => 'fixed'] + 1 => [ + 'option_type_id' => null, + 'title' => 'Option 1 & Value 1"', + 'price' => '1.00', + 'price_type' => 'fixed' + ], + 2 => [ + 'option_type_id' => null, + 'title' => 'Option 1 & Value 2"', + 'price' => '2.00', + 'price_type' => 'fixed' + ], + 3 => [ + 'option_type_id' => null, + 'title' => 'Option 1 & Value 3"', + 'price' => '3.00', + 'price_type' => 'fixed' + ] ] ], [ @@ -52,6 +69,8 @@ 'simple' )->setPrice( 10 +)->addData( + ['text_attribute' => '!@#$%^&*()_+1234567890-=|\\:;"\'<,>.?/'] )->setTierPrice( [0 => ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 8]] )->setVisibility( diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_rollback.php new file mode 100644 index 0000000000000..a4769078a7713 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_rollback.php @@ -0,0 +1,10 @@ +create(\Magento\Catalog\Model\Product::class); + +$productModel->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setId(1) + ->setAttributeSetId(4) + ->setName('New Product') + ->setSku('simple "1"') + ->setPrice(10) + ->addData(['text_attribute' => '!@#$%^&*()_+1234567890-=|\\:;"\'<,>.?/']) + ->setTierPrice([0 => ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 8]]) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setWebsiteIds([1]) + ->setCateroryIds([]) + ->setStockData(['qty' => 100, 'is_in_stock' => 1]) + ->setCanSaveCustomOptions(true) + ->setCategoryIds([333]) + ->setUpSellLinkData([$product->getId() => ['position' => 1]]); + +$productModel->setOptions([])->save(); diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_special_chars_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_special_chars_rollback.php new file mode 100644 index 0000000000000..a4769078a7713 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_data_special_chars_rollback.php @@ -0,0 +1,10 @@ +reinitialize(); + +require dirname(dirname(__DIR__)) . '/Catalog/_files/categories.php'; diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php index fcbf58a44e569..a38a6bfabb789 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data.php @@ -1,11 +1,13 @@ create( diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data_rollback.php new file mode 100644 index 0000000000000..8464dff709121 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/_files/product_export_with_product_links_data_rollback.php @@ -0,0 +1,12 @@ +get(ProductRepositoryInterface::class); + /** @var ProductInterface $product */ + $product = $productRepository->get('simple', false, null, true); + + /** @var ProductExtensionInterface $ea */ + $ea = $product->getExtensionAttributes(); + $ea->getStockItem()->setQty(555); + $productRepository->save($product); + + $product = $productRepository->get('simple', false, null, true); + $this->assertEquals(555, $product->getExtensionAttributes()->getStockItem()->getQty()); + + $stockItem = $product->getExtensionAttributes()->getStockItem(); + $stockItem->setQty(200); + /** @var StockItemRepositoryInterface $stockItemRepository */ + $stockItemRepository = $objectManager->get(StockItemRepositoryInterface::class); + $stockItemRepository->save($stockItem); + $this->assertEquals(200, $product->getExtensionAttributes()->getStockItem()->getQty()); + + $product = $productRepository->get('simple', false, null, true); + $this->assertEquals(200, $product->getExtensionAttributes()->getStockItem()->getQty()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogInventory/Block/Adminhtml/Form/Field/CustomergroupTest.php b/dev/tests/integration/testsuite/Magento/CatalogInventory/Block/Adminhtml/Form/Field/CustomergroupTest.php index cd5f07f9056b3..14d3bd338cf71 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogInventory/Block/Adminhtml/Form/Field/CustomergroupTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogInventory/Block/Adminhtml/Form/Field/CustomergroupTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->observerMock = $this->getMock(Observer::class, [], [], '', false); + $this->optionInitializer = $this->getMock(Option::class, [], [], '', false); + $this->stockState = $this->getMock(StockState::class, [], [], '', false); + $this->quantityValidator = $this->objectManager->create( + QuantityValidator::class, + [ + 'optionInitializer' => $this->optionInitializer, + 'stockState' => $this->stockState + ] + ); + $this->observer = $this->objectManager->create( + QuantityValidatorObserver::class, + [ + 'quantityValidator' => $this->quantityValidator + ] + ); + $this->eventMock = $this->getMock(Event::class, ['getItem'], [], '', false); + } + + /** + * @magentoDataFixture Magento/Checkout/_files/quote_with_bundle_product.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testQuoteWithOptions() + { + /** @var $session \Magento\Checkout\Model\Session */ + $session = $this->objectManager->create(Session::class); + + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + /** @var $product \Magento\Catalog\Model\Product */ + $product = $productRepository->get('bundle-product'); + $resultMock = $this->getMock(DataObject::class, [], [], '', false); + $this->stockState->expects($this->any())->method('checkQtyIncrements')->willReturn($resultMock); + /* @var $quoteItem \Magento\Quote\Model\Quote\Item */ + $quoteItem = $this->_getQuoteItemIdByProductId($session->getQuote(), $product->getId()); + $this->observerMock->expects($this->once())->method('getEvent')->willReturn($this->eventMock); + $this->optionInitializer->expects($this->any())->method('initialize')->willReturn($resultMock); + $this->eventMock->expects($this->once())->method('getItem')->willReturn($quoteItem); + $this->observer->execute($this->observerMock); + $this->assertCount(0, $quoteItem->getErrorInfos(), 'Errors present in QuoteItem when expected 0 errors'); + } + + /** + * @magentoDataFixture Magento/Checkout/_files/quote_with_bundle_product.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testQuoteWithOptionsWithErrors() + { + /** @var $session \Magento\Checkout\Model\Session */ + $session = $this->objectManager->create(Session::class); + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + /** @var $product \Magento\Catalog\Model\Product */ + $product = $productRepository->get('bundle-product'); + /* @var $quoteItem \Magento\Quote\Model\Quote\Item */ + $quoteItem = $this->_getQuoteItemIdByProductId($session->getQuote(), $product->getId()); + $resultMock = $this->getMock( + DataObject::class, + ['checkQtyIncrements', 'getMessage', 'getQuoteMessage', 'getHasError'], + [], + '', + false + ); + $this->observerMock->expects($this->once())->method('getEvent')->willReturn($this->eventMock); + $this->eventMock->expects($this->once())->method('getItem')->willReturn($quoteItem); + $this->stockState->expects($this->any())->method('checkQtyIncrements')->willReturn($resultMock); + $this->optionInitializer->expects($this->any())->method('initialize')->willReturn($resultMock); + $resultMock->expects($this->any())->method('getHasError')->willReturn(true); + $this->observer->execute($this->observerMock); + $this->assertCount(2, $quoteItem->getErrorInfos(), 'Expected 2 errors in QuoteItem'); + } + + /** + * Gets \Magento\Quote\Model\Quote\Item from \Magento\Quote\Model\Quote by product id + * + * @param \Magento\Quote\Model\Quote $quote + * @param $productId + * @return \Magento\Quote\Model\Quote\Item + */ + private function _getQuoteItemIdByProductId($quote, $productId) + { + /** @var $quoteItems \Magento\Quote\Model\Quote\Item[] */ + $quoteItems = $quote->getAllItems(); + foreach ($quoteItems as $quoteItem) { + if ($productId == $quoteItem->getProductId()) { + return $quoteItem; + } + } + $this->fail('Test failed since no quoteItem found by productId '.$productId); + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStockTest.php b/dev/tests/integration/testsuite/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStockTest.php index 02ddb8e23b992..b64b29ae8a656 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStockTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStockTest.php @@ -1,6 +1,6 @@ minSaleQtyConfig = $objectManager->create(Minsaleqty::class); + $this->minSaleQtyConfig->setPath('cataloginventory/item_options/min_sale_qty'); + } + + /** + * Test save and load cycle for minimum sale quantity configuration values. If the passed value is + * valid and non-numeric, it should be json encoded by the serializer, otherwise stored as-is. On load, + * the data will be decoded (if needed) and restructured into a specific hashed array format. + * + * @param bool|string|array $value + * @param string $encodedExpectedValue + * @param array $decodedExpectedValue + * @magentoDbIsolation enabled + * @dataProvider saveAndLoadDataProvider + */ + public function testSaveAndLoad($value, $encodedExpectedValue, array $decodedExpectedValue) + { + $this->minSaleQtyConfig->setValue($value); + $this->minSaleQtyConfig->save(); + $this->assertEquals($encodedExpectedValue, $this->minSaleQtyConfig->getValue()); + + $this->minSaleQtyConfig->load($this->minSaleQtyConfig->getId()); + $hashedConfig = $this->minSaleQtyConfig->getValue(); + + if (!is_array($hashedConfig)) { + $this->fail('Loaded value is not an array, skipping further validation'); + } + + $indexedConfig = array_values($hashedConfig); + $this->assertEquals($decodedExpectedValue, $indexedConfig); + } + + /** + * @return array + */ + public function saveAndLoadDataProvider() + { + $objectManager = Bootstrap::getObjectManager(); + $groupManagement = $objectManager->create(GroupManagementInterface::class); + $allCustomersGroupID = $groupManagement->getAllCustomersGroup()->getId(); + $notLoggedInGroupID = $groupManagement->getNotLoggedInGroup()->getId(); + + return [ + 'bool' => [false, '', []], + 'empty string' => ['', '', []], + 'empty array' => [[], '[]', []], + 'valid numeric - all customer group' => [ + '22', + '22', + [ + [ + 'customer_group_id' => $allCustomersGroupID, + 'min_sale_qty' => 22 + ] + ] + ], + 'invalid named group array' => [ + ['customer_group_id' => 1, 'min_sale_qty' => 2.5], + '{"customer_group_id":1,"min_sale_qty":2.5}', + [ + 0 => [ + 'customer_group_id' => 'customer_group_id', + 'min_sale_qty' => 1 + ], + 1 => [ + 'customer_group_id' => 'min_sale_qty', + 'min_sale_qty' => 2.5 + ] + ] + ], + 'valid array - all customer group' => [ + [['customer_group_id' => $allCustomersGroupID, 'min_sale_qty' => 2.5]], + '2.5', + [ + 0 => [ + 'customer_group_id' => $allCustomersGroupID, + 'min_sale_qty' => 2.5 + ] + ] + ], + 'valid named group' => [ + [['customer_group_id' => 2, 'min_sale_qty' => 2.5]], + '{"2":2.5}', + [ + 0 => [ + 'customer_group_id' => 2, + 'min_sale_qty' => 2.5 + ] + ] + ], + 'invalid - cannot override not logged in group' => [ + [$notLoggedInGroupID => ['min_sale_qty' => 2.5]], + '[1]', + [ + 0 => [ + 'customer_group_id' => $notLoggedInGroupID, + 'min_sale_qty' => 1 + ] + ] + ] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/BatchIndexTest.php b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/BatchIndexTest.php index 9dbd31360221a..ecef1ba4f1cf2 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/BatchIndexTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/BatchIndexTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->indexBuilder = $this->objectManager->get(IndexBuilder::class); + $this->resourceRule = $this->objectManager->get(Rule::class); + $this->resourceRuleCollection = $this->objectManager->get(Collection::class); + } + + /** + * @magentoAppArea adminhtml + * + * @magentoDataFixture Magento/CatalogRule/_files/attribute.php + * @magentoDataFixture Magento/CatalogRule/_files/rule_by_attribute.php + * @magentoDataFixture Magento/CatalogRule/_files/two_rules.php + */ + public function testReindexAfterRuleCreation() + { + $this->indexBuilder->reindexFull(); + $installer = $this->objectManager->create(CategorySetup::class); + + $resourceRuleCollection = $this->objectManager->create(RuleCollection::class); + $resourceRuleCollection->addFilter('is_active', 1); + $this->assertEquals(3, $resourceRuleCollection->count()); + + $resourceRuleCollection = $this->objectManager->create(RuleCollection::class); + $resourceRuleCollection->addFilter('is_active', 1); + $resourceRuleCollection->addFilter('name', 'test_rule'); + $this->assertEquals(1, $resourceRuleCollection->count()); + + $model = $this->objectManager->create(Attribute::class); + $model->loadByCode($installer->getEntityTypeId('catalog_product'), 'test_attribute'); + $model->delete(); + + $resourceRuleCollection = $this->objectManager->create(RuleCollection::class); + $resourceRuleCollection->addFilter('is_active', 1); + $this->assertEquals(2, $resourceRuleCollection->count()); + + $resourceRuleCollection = $this->objectManager->create(RuleCollection::class); + $resourceRuleCollection->addFilter('is_active', 1); + $resourceRuleCollection->addFilter('name', 'test_rule'); + $this->assertEquals(0, $resourceRuleCollection->count()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/RuleTest.php b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/RuleTest.php index 2a4b1e51c5bcb..071cca36a5aa2 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/RuleTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/RuleTest.php @@ -1,6 +1,6 @@ indexSwitcher = $indexSwitcher; + } + + /** + * Switch current index with temporary index + * + * It will drop current index table and rename temporary index table to the current index table. + * + * @param array $dimensions + * @return void + */ + public function switchIndex(array $dimensions) + { + $this->isSwitched |= true; + $this->indexSwitcher->switchIndex($dimensions); + } + + /** + * @return bool + */ + public function isSwitched() + { + return (bool) $this->isSwitched; + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/SwitcherUsedInFulltextTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/SwitcherUsedInFulltextTest.php new file mode 100644 index 0000000000000..a6ddd40dda0df --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/SwitcherUsedInFulltextTest.php @@ -0,0 +1,214 @@ +configure( + [ + ltrim(Fulltext::class, '\\') => [ + 'arguments' => [ + 'indexSwitcher' => [ + 'instance' => ltrim(IndexSwitcherMock::class, '\\'), + ], + ], + ], + ] + ); + + /** @var \Magento\Framework\Indexer\IndexerInterface indexer */ + $this->indexer = $objectManager->create( + \Magento\Indexer\Model\Indexer::class + ); + $this->indexer->load('catalogsearch_fulltext'); + + $this->engine = $objectManager->get( + \Magento\CatalogSearch\Model\ResourceModel\Engine::class + ); + + $this->resourceFulltext = $objectManager->get( + \Magento\CatalogSearch\Model\ResourceModel\Fulltext::class + ); + + $this->queryFactory = $objectManager->get( + \Magento\Search\Model\QueryFactory::class + ); + + $this->dimension = $objectManager->create( + \Magento\Framework\Search\Request\Dimension::class, + ['name' => 'scope', 'value' => '1'] + ); + + $this->indexSwitcher = Bootstrap::getObjectManager()->get( + IndexSwitcherMock::class + ); + + $this->productApple = $this->getProductBySku('fulltext-1'); + $this->productBanana = $this->getProductBySku('fulltext-2'); + $this->productOrange = $this->getProductBySku('fulltext-3'); + $this->productPapaya = $this->getProductBySku('fulltext-4'); + $this->productCherry = $this->getProductBySku('fulltext-5'); + } + + /** + * @magentoAppIsolation enabled + */ + public function testReindexAll() + { + $this->indexer->reindexAll(); + + /** @var IndexSwitcherMock $indexSwitcher */ + $indexSwitcher = Bootstrap::getObjectManager()->get( + IndexSwitcherMock::class + ); + $this->assertTrue($indexSwitcher->isSwitched()); + } + + /** + * @magentoAppIsolation enabled + */ + public function testReindexList() + { + $this->indexer->reindexList([$this->productApple->getId(), $this->productBanana->getId()]); + + /** @var IndexSwitcherMock $indexSwitcher */ + $indexSwitcher = Bootstrap::getObjectManager()->get( + IndexSwitcherMock::class + ); + $this->assertFalse($indexSwitcher->isSwitched()); + } + + /** + * @magentoAppIsolation enabled + */ + public function testReindexRow() + { + $this->indexer->reindexRow($this->productPapaya->getId()); + + /** @var IndexSwitcherMock $indexSwitcher */ + $indexSwitcher = Bootstrap::getObjectManager()->get( + IndexSwitcherMock::class + ); + $this->assertFalse($indexSwitcher->isSwitched()); + } + + /** + * Search the text and return result collection + * + * @param string $text + * @return Product[] + */ + protected function search($text) + { + $this->resourceFulltext->resetSearchResults(); + $query = $this->queryFactory->get(); + $query->unsetData(); + $query->setQueryText($text); + $query->saveIncrementalPopularity(); + $products = []; + $collection = Bootstrap::getObjectManager()->create( + Collection::class, + [ + 'searchRequestName' => 'quick_search_container' + ] + ); + $collection->addSearchFilter($text); + foreach ($collection as $product) { + $products[] = $product; + } + return $products; + } + + /** + * Return product by SKU + * + * @param string $sku + * @return Product + */ + protected function getProductBySku($sku) + { + /** @var Product $product */ + $product = Bootstrap::getObjectManager()->get( + \Magento\Catalog\Model\Product::class + ); + return $product->loadByAttribute('sku', $sku); + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/AttributeTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/AttributeTest.php index 9e217495981a5..02338012bd6f4 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Layer/Filter/AttributeTest.php @@ -1,6 +1,6 @@ create( diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/_files/indexer_fulltext.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/_files/indexer_fulltext.php index f6a4b9488b331..864a1d538f40d 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/_files/indexer_fulltext.php +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/_files/indexer_fulltext.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); } - public function tearDown() - { - $category = $this->objectManager->create(\Magento\Catalog\Model\Category::class); - $category->load(3); - $category->delete(); - } - /** * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php * @magentoDbIsolation enabled @@ -96,6 +89,37 @@ public function testGenerateUrlRewritesWithSaveHistory() $this->assertResults($categoryExpectedResult, $actualResults); } + /** + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @param string $urlKey + * @dataProvider incorrectUrlRewritesDataProvider + */ + public function testGenerateUrlRewritesWithIncorrectUrlKey($urlKey) + { + $this->setExpectedException( + \Magento\Framework\Exception\LocalizedException::class, + 'Invalid URL key' + ); + /** @var \Magento\Catalog\Api\CategoryRepositoryInterface $repository */ + $repository = $this->objectManager->get(\Magento\Catalog\Api\CategoryRepositoryInterface::class); + $category = $repository->get(3); + $category->setUrlKey($urlKey); + $repository->save($category); + } + + /** + * @return array + */ + public function incorrectUrlRewritesDataProvider() + { + return [ + ['#'], + ['//'] + ]; + } + /** * @param array $filter * @return array diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserverTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserverTest.php new file mode 100644 index 0000000000000..101ce61c779dc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/CategoryProcessUrlRewriteSavingObserverTest.php @@ -0,0 +1,188 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @param array $filter + * @return array + */ + private function getActualResults(array $filter) + { + /** @var \Magento\UrlRewrite\Model\UrlFinderInterface $urlFinder */ + $urlFinder = $this->objectManager->get(\Magento\UrlRewrite\Model\UrlFinderInterface::class); + $actualResults = []; + foreach ($urlFinder->findAllByData($filter) as $url) { + $actualResults[] = [ + 'request_path' => $url->getRequestPath(), + 'target_path' => $url->getTargetPath(), + 'is_auto_generated' => (int)$url->getIsAutogenerated(), + 'redirect_type' => $url->getRedirectType() + ]; + } + return $actualResults; + } + + public function tearDown() + { + $category = $this->objectManager->create(\Magento\Catalog\Model\Category::class); + $category->load(3); + $category->delete(); + } + + /** + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testUrlKeyHasChanged() + { + $categoryFilter = [ + UrlRewrite::ENTITY_TYPE => 'category', + ]; + $expected = [ + [ + 'request_path' => "category-1.html", + 'target_path' => "catalog/category/view/id/3", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "category-1/category-1-1.html", + 'target_path' => "catalog/category/view/id/4", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "category-1/category-1-1/category-1-1-1.html", + 'target_path' => "catalog/category/view/id/5", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "category-2.html", + 'target_path' => "catalog/category/view/id/6", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ] + + ]; + $actual = $this->getActualResults($categoryFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + /** @var \Magento\Catalog\Model\Category $category */ + $category = $this->objectManager->create(\Magento\Catalog\Model\Category::class); + $category->load(3); + $category->setData('save_rewrites_history', false); + $category->setUrlKey('new-url'); + $category->save(); + $expected = [ + [ + 'request_path' => "new-url.html", + 'target_path' => "catalog/category/view/id/3", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "new-url/category-1-1.html", + 'target_path' => "catalog/category/view/id/4", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "new-url/category-1-1/category-1-1-1.html", + 'target_path' => "catalog/category/view/id/5", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "category-2.html", + 'target_path' => "catalog/category/view/id/6", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ] + + ]; + $actual = $this->getActualResults($categoryFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + } + + /** + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories_with_products.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testIsAnchorHasChanged() + { + $categoryFilter = [ + UrlRewrite::ENTITY_TYPE => CategoryUrlRewriteGenerator::ENTITY_TYPE, + ]; + /** @var \Magento\Catalog\Model\Category $category */ + $category = $this->objectManager->create(\Magento\Catalog\Model\Category::class); + $category->load(3); + $category->setData('is_anchor', false); + $category->save(); + $expected = [ + [ + 'request_path' => "category-1.html", + 'target_path' => "catalog/category/view/id/3", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "category-1/category-1-1.html", + 'target_path' => "catalog/category/view/id/4", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "category-1/category-1-1/category-1-1-1.html", + 'target_path' => "catalog/category/view/id/5", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ], + [ + 'request_path' => "category-2.html", + 'target_path' => "catalog/category/view/id/6", + 'is_auto_generated' => 1, + 'redirect_type' => 0 + ] + + ]; + $actual = $this->getActualResults($categoryFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php index 1a5a6f87ff1c2..b67d1b234a7ed 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Block/Adminhtml/Category/Tab/AttributesTest.php @@ -1,6 +1,6 @@ _objectManager->create(\Magento\Checkout\Model\Session::class); + $quote = $session->getQuote(); + $quote->setData('trigger_recollect', 1)->setTotalsCollectedFlag(true); + $inputData = [ + 'remove' => 0, + 'coupon_code' => 'test' + ]; + $this->getRequest()->setPostValue($inputData); + $this->dispatch( + 'checkout/cart/couponPost/' + ); + + $this->assertSessionMessages( + $this->equalTo(['The coupon code "test" is not valid.']), + \Magento\Framework\Message\MessageInterface::TYPE_ERROR + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php b/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php index 34a484f749b78..b7d9095a6b4da 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/Controller/CartTest.php @@ -1,6 +1,6 @@ _objectManager->get(\Magento\Framework\Data\Form\FormKey::class); + $postData = [ + 'qty' => '1', + 'product' => '1', + 'custom_price' => 1, + 'form_key' => $formKey->getFormKey(), + 'isAjax' => 1 + ]; + \Magento\TestFramework\Helper\Bootstrap::getInstance()->loadArea($area); + $this->getRequest()->setPostValue($postData); + + $quote = $this->_objectManager->create(\Magento\Checkout\Model\Cart::class); + /** @var \Magento\Checkout\Controller\Cart\Add $controller */ + $controller = $this->_objectManager->create(\Magento\Checkout\Controller\Cart\Add::class, [$quote]); + $controller->execute(); + + $this->assertContains(json_encode([]), $this->getResponse()->getBody()); + $items = $quote->getItems()->getItems(); + $this->assertTrue(is_array($items), 'Quote doesn\'t have any items'); + $this->assertCount(1, $items, 'Expected quote items not equal to 1'); + $item = reset($items); + $this->assertEquals(1, $item->getProductId(), 'Quote has more than one product'); + $this->assertEquals($expectedPrice, $item->getPrice(), 'Expected product price failed'); + } + + /** + * Data provider for testAddToCartSimpleProduct + */ + public function addAddProductDataProvider() + { + return [ + 'frontend' => ['frontend', 'expected_price' => 10], + 'adminhtml' => ['adminhtml', 'expected_price' => 1] + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Checkout/Model/CartTest.php b/dev/tests/integration/testsuite/Magento/Checkout/Model/CartTest.php index 4c3892acfb223..8371b2cccf916 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/Model/CartTest.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/Model/CartTest.php @@ -1,6 +1,6 @@ create(\Magento\Quote\Model\Quote::class); diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_rollback.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_rollback.php index 91763519d829d..905af344badfe 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_rollback.php @@ -1,6 +1,6 @@ collectTotals()->save(); + +$quoteRepository = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Quote\Api\CartRepositoryInterface::class +); +$quoteRepository->save($quote); /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_saved_rollback.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_saved_rollback.php index 069357a7234d6..ba645ce1af486 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_saved_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_saved_rollback.php @@ -2,7 +2,7 @@ /** * Rollback for quote_with_address_saved.php fixture. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_bundle_and_options.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_bundle_and_options.php index ef0935374bfd5..d3ef5f87db48b 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_bundle_and_options.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_bundle_and_options.php @@ -1,6 +1,6 @@ create(\Magento\Framework\Serialize\Serializer\Json::class); + $quote->setReservedOrderId( 'test_order_1_with_payment' ); @@ -22,7 +25,7 @@ ->setCcType('visa') ->setCcExpYear(2014) ->setCcExpMonth(1) - ->setAdditionalData(serialize($paymentDetails)); + ->setAdditionalData($serializer->serialize($paymentDetails)); $quote->collectTotals()->save(); diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved_rollback.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved_rollback.php index 33b756717a63f..b690891541f9d 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_payment_saved_rollback.php @@ -2,7 +2,7 @@ /** * Rollback for quote_with_payment_saved.php fixture. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_product_and_payment.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_product_and_payment.php index 82098bcec046c..fbad5c1b8ea60 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_product_and_payment.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_product_and_payment.php @@ -1,6 +1,6 @@ setId( 444 )->setAttributeSetId( - 5 + 4 )->setStoreId( 1 )->setWebsiteIds( diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_rollback.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_rollback.php index a6c8d6cf2f5c2..1445ce39282be 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_shipping_method_rollback.php @@ -2,7 +2,7 @@ /** * Rollback for quote_with_shipping_method.php fixture. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ require 'quote_with_address_saved_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_simple_product.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_simple_product.php index ba92825089f55..ca6748d04502c 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_simple_product.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_simple_product.php @@ -1,6 +1,6 @@ assertEquals($expectedIdentifier, $page->getIdentifier()); } + /** + * @magentoDbIsolation enabled + */ + public function testUpdateTime() + { + $updateTime = '2016-09-01 00:00:00'; + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Cms\Model\Page $page */ + $page = $objectManager->create(\Magento\Cms\Model\Page::class); + $page->setData(['title' => 'Test', 'stores' => [1]]); + $page->setUpdateTime($updateTime); + $page->save(); + $page = $objectManager->get(PageRepositoryInterface::class)->getById($page->getId()); + $this->assertEquals($updateTime, $page->getUpdateTime()); + } + public function generateIdentifierFromTitleDataProvider() { return [ diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php index a5f5718d17c1e..a05ac0e506694 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php @@ -1,6 +1,6 @@ _model->getConfig(); - $publicPathPattern = 'http://localhost/pub/static/adminhtml/Magento/backend/en_US/mage/%s'; + $publicPathPattern = 'http://localhost/pub/static/%s/adminhtml/Magento/backend/en_US/mage/%s'; $this->assertStringMatchesFormat($publicPathPattern, $config->getPopupCss()); $this->assertStringMatchesFormat($publicPathPattern, $config->getContentCss()); } diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php index 40a97894fc55c..37b42cf7bb87c 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php @@ -1,6 +1,6 @@ assertInstanceOf(\Magento\Framework\DataObject::class, $item); $this->assertStringEndsWith('/1.swf', $item->getUrl()); $this->assertStringMatchesFormat( - 'http://%s/static/adminhtml/%s/%s/Magento_Cms/images/placeholder_thumbnail.jpg', + 'http://%s/static/%s/adminhtml/%s/%s/Magento_Cms/images/placeholder_thumbnail.jpg', $item->getThumbUrl() ); return; diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/block.php b/dev/tests/integration/testsuite/Magento/Cms/_files/block.php index 7f897d90c0ac2..726a956ca725d 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/_files/block.php +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/block.php @@ -1,6 +1,6 @@ create(\Magento\Cms\Model\Page::class); diff --git a/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php b/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php index 533ae1e9bc649..d3bc2b649ef1a 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php +++ b/dev/tests/integration/testsuite/Magento/Cms/_files/pages.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php new file mode 100644 index 0000000000000..724c379cc9511 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php @@ -0,0 +1,421 @@ +objectManager = Bootstrap::getObjectManager(); + $this->scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $this->reader = $this->objectManager->get(Reader::class); + $this->filesystem = $this->objectManager->get(Filesystem::class); + $this->configFilePool = $this->objectManager->get(ConfigFilePool::class); + $this->arrayManager = $this->objectManager->get(ArrayManager::class); + + // Snapshot of configuration. + $this->config = $this->loadConfig(); + + // Mocks for objects. + $this->inputMock = $this->getMockBuilder(InputInterface::class) + ->getMockForAbstractClass(); + $this->outputMock = $this->getMockBuilder(OutputInterface::class) + ->getMockForAbstractClass(); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile( + $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG), + "objectManager->get(Writer::class); + $writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]); + } + + /** + * @return array + */ + private function loadConfig() + { + return $this->reader->loadConfigFile( + ConfigFilePool::APP_CONFIG, + $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG), + true + ); + } + + /** + * Tests default (database) flow. + * Expects to save value and then error on saving duplicate value. + * + * @param string $path + * @param string|int $value + * @param string $scope + * @param string $scopeCode + * @magentoDbIsolation enabled + * @dataProvider runDataProvider + */ + public function testRun($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + { + $this->inputMock->expects($this->any()) + ->method('getArgument') + ->willReturnMap([ + [ConfigSetCommand::ARG_PATH, $path], + [ConfigSetCommand::ARG_VALUE, $value], + ]); + $this->inputMock->expects($this->any()) + ->method('getOption') + ->willReturnMap([ + [ConfigSetCommand::OPTION_LOCK, false], + [ConfigSetCommand::OPTION_SCOPE, $scope], + [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode], + ]); + $this->outputMock->expects($this->once()) + ->method('writeln') + ->withConsecutive( + ['Value was saved.'] + ); + + /** @var ConfigSetCommand $command */ + $command = $this->objectManager->create(ConfigSetCommand::class); + $status = $command->run($this->inputMock, $this->outputMock); + + $this->assertSame(Cli::RETURN_SUCCESS, $status); + $this->assertSame( + $value, + $this->scopeConfig->getValue($path, $scope, $scopeCode) + ); + } + + /** + * Retrieves variations with path, value, scope and scope code. + * + * @return array + */ + public function runDataProvider() + { + return [ + ['test/test/test', 'value'], + ['test/test/test2', 'value2', ScopeInterface::SCOPE_WEBSITE, 'base'] + ]; + } + + /** + * Tests lockable flow. + * Expects to save value and then error on saving duplicate value. + * + * @param string $path + * @param string $value + * @param string $scope + * @param string $scopeCode + * @magentoDbIsolation enabled + * @dataProvider runLockDataProvider + */ + public function testRunLock($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + { + $this->inputMock->expects($this->any()) + ->method('getArgument') + ->willReturnMap([ + [ConfigSetCommand::ARG_PATH, $path], + [ConfigSetCommand::ARG_VALUE, $value] + ]); + $this->inputMock->expects($this->any()) + ->method('getOption') + ->willReturnMap([ + [ConfigSetCommand::OPTION_LOCK, true], + [ConfigSetCommand::OPTION_SCOPE, $scope], + [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode] + ]); + $this->outputMock->expects($this->exactly(2)) + ->method('writeln') + ->withConsecutive( + ['Value was saved and locked.'], + ['Value was saved and locked.'] + ); + + /** @var ConfigSetCommand $command */ + $command = $this->objectManager->create(ConfigSetCommand::class); + /** @var ConfigPathResolver $resolver */ + $resolver = $this->objectManager->get(ConfigPathResolver::class); + $status = $command->run($this->inputMock, $this->outputMock); + $configPath = $resolver->resolve($path, $scope, $scopeCode, 'system'); + + $this->assertSame(Cli::RETURN_SUCCESS, $status); + $this->assertSame($value, $this->arrayManager->get($configPath, $this->loadConfig())); + + $status = $command->run($this->inputMock, $this->outputMock); + + $this->assertSame(Cli::RETURN_SUCCESS, $status); + } + + /** + * Retrieves variations with path, value, scope and scope code. + * + * @return array + */ + public function runLockDataProvider() + { + return $this->runDataProvider(); + } + + /** + * Tests the extended flow. + * + * @param string $path + * @param string $value + * @param string $scope + * @param string $scopeCode + * @magentoDbIsolation enabled + * @dataProvider runExtendedDataProvider + */ + public function testRunExtended( + $path, + $value, + $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + $scopeCode = null + ) { + $arguments = [ + [ConfigSetCommand::ARG_PATH, $path], + [ConfigSetCommand::ARG_VALUE, $value] + ]; + $options = [ + [ConfigSetCommand::OPTION_SCOPE, $scope], + [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode] + ]; + $optionsLock = array_merge($options, [[ConfigSetCommand::OPTION_LOCK, true]]); + + /** @var ConfigPathResolver $resolver */ + $resolver = $this->objectManager->get(ConfigPathResolver::class); + /** @var array $configPath */ + $configPath = $resolver->resolve($path, $scope, $scopeCode, 'system'); + + $this->runCommand($arguments, $options, 'Value was saved.'); + $this->runCommand($arguments, $options, 'Value was saved.'); + + $this->assertSame( + $value, + $this->scopeConfig->getValue($path, $scope, $scopeCode) + ); + $this->assertSame(null, $this->arrayManager->get($configPath, $this->loadConfig())); + + $this->runCommand($arguments, $optionsLock, 'Value was saved and locked.'); + $this->runCommand($arguments, $optionsLock, 'Value was saved and locked.'); + + $this->assertSame($value, $this->arrayManager->get($configPath, $this->loadConfig())); + } + + /** + * Runs pre-configured command. + * + * @param array $arguments + * @param array $options + * @param string $expectedMessage + * @param int $expectedCode + */ + private function runCommand( + array $arguments, + array $options, + $expectedMessage = '', + $expectedCode = Cli::RETURN_SUCCESS + ) { + $input = clone $this->inputMock; + $output = clone $this->outputMock; + + $input->expects($this->any()) + ->method('getArgument') + ->willReturnMap($arguments); + $input->expects($this->any()) + ->method('getOption') + ->willReturnMap($options); + $output->expects($this->once()) + ->method('writeln') + ->with($expectedMessage); + + /** @var ConfigSetCommand $command */ + $command = $this->objectManager->create(ConfigSetCommand::class); + $status = $command->run($input, $output); + + $this->assertSame($expectedCode, $status); + } + + /** + * Retrieves variations with path, value, scope and scope code. + * + * @return array + */ + public function runExtendedDataProvider() + { + return $this->runDataProvider(); + } + + /** + * Tests different scenarios for scope options. + * + * @param \Closure $expectations + * @param string $path + * @param string $value + * @param string $scope + * @param string $scopeCode + * @magentoDbIsolation enabled + * @dataProvider getRunScopeValidationDataProvider + */ + public function testRunScopeValidation( + \Closure $expectations, + $path, + $value, + $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + $scopeCode = null + ) { + $this->inputMock->expects($this->any()) + ->method('getArgument') + ->willReturnMap([ + [ConfigSetCommand::ARG_PATH, $path], + [ConfigSetCommand::ARG_VALUE, $value] + ]); + $this->inputMock->expects($this->any()) + ->method('getOption') + ->willReturnMap([ + [ConfigSetCommand::OPTION_SCOPE, $scope], + [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode] + ]); + + $expectations($this->outputMock); + + /** @var ConfigSetCommand $command */ + $command = $this->objectManager->create(ConfigSetCommand::class); + $command->run($this->inputMock, $this->outputMock); + } + + /** + * Retrieves variations with callback, path, value, scope and scope code. + * + * @return array + */ + public function getRunScopeValidationDataProvider() + { + return [ + [ + function (Mock $output) { + $output->expects($this->once()) + ->method('writeln') + ->with('Value was saved.'); + }, + 'test/test/test', + 'value', + ScopeInterface::SCOPE_WEBSITE, + 'base' + ], + [ + function (Mock $output) { + $output->expects($this->once()) + ->method('writeln') + ->with('Enter a scope before proceeding.'); + }, + 'test/test/test', + null, + null, + null + + ], + [ + function (Mock $output) { + $output->expects($this->once()) + ->method('writeln') + ->with('Enter a scope code before proceeding.'); + }, + 'test/test/test', + 'value', + ScopeInterface::SCOPE_WEBSITE, + ], + [ + function (Mock $output) { + $output->expects($this->once()) + ->method('writeln') + ->with('The "invalid_scope_code" value doesn\'t exist. Enter another value.'); + }, + 'test/test/test', + 'value', + ScopeInterface::SCOPE_WEBSITE, + 'invalid_scope_code' + ] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigShowCommandTest.php b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigShowCommandTest.php new file mode 100644 index 0000000000000..596729fc107ac --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigShowCommandTest.php @@ -0,0 +1,312 @@ +objectManager = Bootstrap::getObjectManager(); + $this->configFilePool = $this->objectManager->get(ConfigFilePool::class); + $this->filesystem = $this->objectManager->get(Filesystem::class); + $this->reader = $this->objectManager->get(Reader::class); + $this->writer = $this->objectManager->get(Writer::class); + + $this->config = $this->loadConfig(); + $this->env = $_ENV; + + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile( + $this->getFileName(), + file_get_contents(__DIR__ . '/../../_files/_config.local.php') + ); + + $config = include(__DIR__ . '/../../_files/_config.php'); + $this->writer->saveConfig([ConfigFilePool::APP_CONFIG => $config]); + + $_ENV['CONFIG__DEFAULT__WEB__TEST2__TEST_VALUE_4'] = 'value4.env.default.test'; + $_ENV['CONFIG__WEBSITES__BASE__WEB__TEST2__TEST_VALUE_4'] = 'value4.env.website_base.test'; + $_ENV['CONFIG__STORES__DEFAULT__WEB__TEST2__TEST_VALUE_4'] = 'value4.env.store_default.test'; + + $command = $this->objectManager->create(ConfigShowCommand::class); + $this->commandTester = new CommandTester($command); + } + + /** + * @param string $scope + * @param string $scopeCode + * @param int $resultCode + * @param array $configs + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Config/_files/config_data.php + * @dataProvider executeDataProvider + */ + public function testExecute($scope, $scopeCode, $resultCode, array $configs) + { + foreach ($configs as $inputPath => $configValue) { + $arguments = [ + ConfigShowCommand::INPUT_ARGUMENT_PATH => $inputPath + ]; + + if ($scope !== null) { + $arguments['--' . ConfigShowCommand::INPUT_OPTION_SCOPE] = $scope; + } + if ($scopeCode !== null) { + $arguments['--' . ConfigShowCommand::INPUT_OPTION_SCOPE_CODE] = $scopeCode; + } + + $this->commandTester->execute($arguments); + + $this->assertEquals( + $resultCode, + $this->commandTester->getStatusCode() + ); + + $commandOutput = $this->commandTester->getDisplay(); + foreach ($configValue as $value) { + $this->assertContains($value, $commandOutput); + } + } + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function executeDataProvider() + { + return [ + [ + null, + null, + Cli::RETURN_SUCCESS, + [ + 'web/test/test_value_1' => ['value1.db.default.test'], + 'web/test/test_value_2' => ['value2.local_config.default.test'], + 'web/test2/test_value_3' => ['value3.config.default.test'], + 'web/test2/test_value_4' => ['value4.env.default.test'], + 'web/test' => [ + 'web/test/test_value_1 - value1.db.default.test', + 'web/test/test_value_2 - value2.local_config.default.test', + ], + 'web/test2' => [ + 'web/test2/test_value_3 - value3.config.default.test', + 'web/test2/test_value_4 - value4.env.default.test', + ], + 'web' => [ + 'web/test/test_value_1 - value1.db.default.test', + 'web/test/test_value_2 - value2.local_config.default.test', + 'web/test2/test_value_3 - value3.config.default.test', + 'web/test2/test_value_4 - value4.env.default.test', + ], + '' => [ + 'web/test/test_value_1 - value1.db.default.test', + 'web/test/test_value_2 - value2.local_config.default.test', + 'web/test2/test_value_3 - value3.config.default.test', + 'web/test2/test_value_4 - value4.env.default.test', + ], + ] + ], + [ + ScopeInterface::SCOPE_WEBSITES, + 'base', + Cli::RETURN_SUCCESS, + [ + 'web/test/test_value_1' => ['value1.db.website_base.test'], + 'web/test/test_value_2' => ['value2.local_config.website_base.test'], + 'web/test2/test_value_3' => ['value3.config.website_base.test'], + 'web/test2/test_value_4' => ['value4.env.website_base.test'], + 'web/test' => [ + 'web/test/test_value_1 - value1.db.website_base.test', + 'web/test/test_value_2 - value2.local_config.website_base.test', + ], + 'web/test2' => [ + 'web/test2/test_value_3 - value3.config.website_base.test', + 'web/test2/test_value_4 - value4.env.website_base.test', + ], + 'web' => [ + 'web/test/test_value_1 - value1.db.website_base.test', + 'web/test/test_value_2 - value2.local_config.website_base.test', + 'web/test2/test_value_3 - value3.config.website_base.test', + 'web/test2/test_value_4 - value4.env.website_base.test', + ], + '' => [ + 'web/test/test_value_1 - value1.db.website_base.test', + 'web/test/test_value_2 - value2.local_config.website_base.test', + 'web/test2/test_value_3 - value3.config.website_base.test', + 'web/test2/test_value_4 - value4.env.website_base.test', + ], + ] + ], + [ + ScopeInterface::SCOPE_STORES, + 'default', + Cli::RETURN_SUCCESS, + [ + 'web/test/test_value_1' => ['value1.db.store_default.test'], + 'web/test/test_value_2' => ['value2.local_config.store_default.test'], + 'web/test2/test_value_3' => ['value3.config.store_default.test'], + 'web/test2/test_value_4' => ['value4.env.store_default.test'], + 'web/test' => [ + 'web/test/test_value_1 - value1.db.store_default.test', + 'web/test/test_value_2 - value2.local_config.store_default.test', + ], + 'web/test2' => [ + 'web/test2/test_value_3 - value3.config.store_default.test', + 'web/test2/test_value_4 - value4.env.store_default.test', + ], + 'web' => [ + 'web/test/test_value_1 - value1.db.store_default.test', + 'web/test/test_value_2 - value2.local_config.store_default.test', + 'web/test2/test_value_3 - value3.config.store_default.test', + 'web/test2/test_value_4 - value4.env.store_default.test', + ], + '' => [ + 'web/test/test_value_1 - value1.db.store_default.test', + 'web/test/test_value_2 - value2.local_config.store_default.test', + 'web/test2/test_value_3 - value3.config.store_default.test', + 'web/test2/test_value_4 - value4.env.store_default.test', + ], + ] + ], + [ + null, + null, + Cli::RETURN_FAILURE, + [ + 'web/test/test_wrong_value' => [ + 'Configuration for path: "web/test/test_wrong_value" doesn\'t exist' + ], + ] + ], + [ + 'default', + null, + Cli::RETURN_FAILURE, + [ + 'web/test/test_wrong_value' => [ + 'Configuration for path: "web/test/test_wrong_value" doesn\'t exist' + ], + ] + ], + [ + 'default', + 'scope_code', + Cli::RETURN_FAILURE, + [ + 'web/test/test_wrong_value' => [ + 'The "default" scope can\'t include a scope code. Try again without entering a scope code.' + ], + ] + ], + [ + 'some_scope', + 'scope_code', + Cli::RETURN_FAILURE, + [ + 'web/test/test_wrong_value' => [ + 'The "some_scope" value doesn\'t exist. Enter another value.' + ], + ] + ], + [ + 'websites', + 'scope_code', + Cli::RETURN_FAILURE, + [ + 'web/test/test_wrong_value' => [ + 'The "scope_code" value doesn\'t exist. Enter another value.' + ], + ] + ], + ]; + } + + /** + * @return string + */ + private function getFileName() + { + $filePool = $this->configFilePool->getInitialFilePools(); + + return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG]; + } + + /** + * @return array + */ + private function loadConfig() + { + return $this->reader->loadConfigFile( + ConfigFilePool::APP_CONFIG, + $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG), + true + ); + } + + public function tearDown() + { + $_ENV = $this->env; + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->delete( + $this->getFileName() + ); + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile( + $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG), + "writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Config/Controller/Adminhtml/System/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Config/Controller/Adminhtml/System/ConfigTest.php index 22978b113a527..3d31c1242a8d0 100644 --- a/dev/tests/integration/testsuite/Magento/Config/Controller/Adminhtml/System/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Config/Controller/Adminhtml/System/ConfigTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $this->objectManager->get(EnvironmentPlaceholder::class); + $this->env = $_ENV; + } + + public function testProcess() + { + $_ENV = array_merge( + $_ENV, + [ + 'CONFIG__DEFAULT__WEB__UNSECURE__BASE_URL' => 'http://expected.local', + 'CONFIG__TEST__TEST__DESIGN__HEADER__WELCOME' => 'Expected header', + 'TEST__TEST__WEB__SECURE__BASE_URL' => 'http://wrong_pattern.local', + 'CONFIG__DEFAULT__GENERAL__REGION__DISPLAY_ALL' => 1 + ] + ); + $expected = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://expected.local' + ], + 'secure' => [ + 'base_url' => 'https://original.local' + ] + ], + 'general' => [ + 'region' => [ + 'display_all' => 1 + ], + ], + ], + 'test' => [ + 'test' => [ + 'design' => [ + 'header' => [ + 'welcome' => 'Expected header' + ] + ], + ], + ] + ]; + $config = [ + 'default' => [ + 'web' => [ + 'unsecure' => [ + 'base_url' => 'http://original.local', + ], + 'secure' => [ + 'base_url' => 'https://original.local' + ] + ] + ], + 'test' => [ + 'test' => [ + 'design' => [ + 'header' => [ + 'welcome' => 'Original header' + ] + ], + ], + ] + ]; + + $this->assertSame( + $expected, + $this->model->process($config) + ); + } + + protected function tearDown() + { + $_ENV = $this->env; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Config/Model/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Config/Model/ConfigTest.php index a0560271f7beb..1f59728d1796f 100644 --- a/dev/tests/integration/testsuite/Magento/Config/Model/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Config/Model/ConfigTest.php @@ -1,6 +1,6 @@ [ + 'default' => [ + 'web' => [ + 'test' => [ + 'test_value_2' => 'value2.local_config.default.test', + ], + 'test2' => [ + 'test_value_3' => 'value3.local_config.default.test', + 'test_value_4' => 'value4.local_config.default.test', + ], + ], + ], + 'websites' => [ + 'base' => [ + 'web' => [ + 'test' => [ + 'test_value_2' => 'value2.local_config.website_base.test', + ], + 'test2' => [ + 'test_value_3' => 'value3.local_config.website_base.test', + 'test_value_4' => 'value4.local_config.website_base.test', + ], + ], + ], + ], + 'stores' => [ + 'default' => [ + 'web' => [ + 'test' => [ + 'test_value_2' => 'value2.local_config.store_default.test', + ], + 'test2' => [ + 'test_value_3' => 'value3.local_config.store_default.test', + 'test_value_4' => 'value4.local_config.store_default.test', + ], + ], + ], + ], + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/Config/_files/_config.php b/dev/tests/integration/testsuite/Magento/Config/_files/_config.php new file mode 100644 index 0000000000000..79eb6e7e12db8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/_files/_config.php @@ -0,0 +1,37 @@ + [ + 'default' => [ + 'web' => [ + 'test2' => [ + 'test_value_3' => 'value3.config.default.test', + 'test_value_4' => 'value4.config.default.test', + ], + ], + ], + 'websites' => [ + 'base' => [ + 'web' => [ + 'test2' => [ + 'test_value_3' => 'value3.config.website_base.test', + 'test_value_4' => 'value4.config.website_base.test', + ], + ], + ], + ], + 'stores' => [ + 'default' => [ + 'web' => [ + 'test2' => [ + 'test_value_3' => 'value3.config.store_default.test', + 'test_value_4' => 'value4.config.store_default.test', + ], + ], + ], + ], + ], +]; diff --git a/dev/tests/integration/testsuite/Magento/Config/_files/config_data.php b/dev/tests/integration/testsuite/Magento/Config/_files/config_data.php new file mode 100644 index 0000000000000..9b9c2fe6c826a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/_files/config_data.php @@ -0,0 +1,61 @@ + [ + '' => [ + 'web/test/test_value_1' => 'value1.db.default.test', + 'web/test/test_value_2' => 'value2.db.default.test', + 'web/test2/test_value_3' => 'value3.db.default.test', + 'web/test2/test_value_4' => 'value4.db.default.test', + ] + ], + ScopeInterface::SCOPE_WEBSITES => [ + 'base' => [ + 'web/test/test_value_1' => 'value1.db.website_base.test', + 'web/test/test_value_2' => 'value2.db.website_base.test', + 'web/test2/test_value_3' => 'value3.db.website_base.test', + 'web/test2/test_value_4' => 'value4.db.website_base.test', + ] + ], + ScopeInterface::SCOPE_STORES => [ + 'default' => [ + 'web/test/test_value_1' => 'value1.db.store_default.test', + 'web/test/test_value_2' => 'value2.db.store_default.test', + 'web/test2/test_value_3' => 'value3.db.store_default.test', + 'web/test2/test_value_4' => 'value4.db.store_default.test', + ] + ], +]; + +$objectManager = Bootstrap::getObjectManager(); +/** @var Factory $configFactory */ +$configFactory = $objectManager->create(Factory::class); + +foreach ($configData as $scope => $data) { + foreach ($data as $scopeCode => $scopeData) { + foreach ($scopeData as $path => $value) { + $config = $configFactory->create(); + $config->setScope($scope); + + if ($scope == ScopeInterface::SCOPE_WEBSITES) { + $config->setWebsite($scopeCode); + } + + if ($scope == ScopeInterface::SCOPE_STORES) { + $config->setStore($scopeCode); + } + + $config->setDataByPath($path, $value); + $config->save(); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php index 1b9a4d5eabcaa..74a82f0349a13 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php @@ -1,6 +1,6 @@ [ + [ + 'Magento/ConfigurableProduct/_files/product_configurable_12345.php' + ], + [ + '12345', + ], + ['_cache_instance_products', '_cache_instance_configurable_attributes'], + ], ]; } @@ -107,7 +116,6 @@ public function importReplaceDataProvider() */ public function testImportReplace($fixtures, $skus, $skippedAttributes = []) { - $this->markTestSkipped('MAGETWO-56530'); parent::testImportReplace($fixtures, $skus, $skippedAttributes); } } diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php index ececb3bd0a3d9..814f72dc564c5 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Export/RowCustomizerTest.php @@ -1,6 +1,6 @@ productMetadata = $metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class); } + public function configurableImportDataProvider() + { + return [ + 'Configurable 1' => [ + __DIR__ . '/../../_files/import_configurable.csv', + 'Configurable 1', + ['Configurable 1-Option 1', 'Configurable 1-Option 2'], + ], + '12345' => [ + __DIR__ . '/../../_files/import_configurable_12345.csv', + '12345', + ['Configurable 1-Option 1', 'Configurable 1-Option 2'], + ], + ]; + } + /** + * @param $pathToFile Path to import file + * @param $productName Name/sku of configurable product + * @param $optionSkuList Name of variations for configurable product * @magentoDataFixture Magento/ConfigurableProduct/_files/configurable_attribute.php * @magentoAppArea adminhtml + * @dataProvider configurableImportDataProvider */ - public function testConfigurableImport() + public function testConfigurableImport($pathToFile, $productName, $optionSkuList) { - // import data from CSV file - $pathToFile = __DIR__ . '/../../_files/import_configurable.csv'; $filesystem = $this->objectManager->create( \Magento\Framework\Filesystem::class ); @@ -90,23 +96,23 @@ public function testConfigurableImport() /** @var \Magento\Catalog\Model\ResourceModel\Product $resource */ $resource = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Product::class); - $productId = $resource->getIdBySku(self::TEST_PRODUCT_NAME); + $productId = $resource->getIdBySku($productName); $this->assertTrue(is_numeric($productId)); /** @var \Magento\Catalog\Model\Product $product */ $product = $this->objectManager->get(ProductRepositoryInterface::class)->getById($productId); $this->assertFalse($product->isObjectNew()); - $this->assertEquals(self::TEST_PRODUCT_NAME, $product->getName()); + $this->assertEquals($productName, $product->getName()); $this->assertEquals(self::TEST_PRODUCT_TYPE, $product->getTypeId()); $optionCollection = $product->getTypeInstance()->getConfigurableOptions($product); foreach ($optionCollection as $option) { foreach ($option as $optionData) { - $this->assertContains($optionData['sku'], $this->optionSkuList); + $this->assertContains($optionData['sku'], $optionSkuList); } } - $optionIdList = $resource->getProductsIdsBySkus($this->optionSkuList); + $optionIdList = $resource->getProductsIdsBySkus($optionSkuList); foreach ($optionIdList as $optionId) { $this->assertArrayHasKey($optionId, $product->getExtensionAttributes()->getConfigurableProductLinks()); } diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable_12345.csv b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable_12345.csv new file mode 100644 index 0000000000000..02cfb46e920ca --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/Import/_files/import_configurable_12345.csv @@ -0,0 +1,4 @@ +sku,store_view_code,attribute_set_code,product_type,name,description,short_description,weight,product_online,tax_class_name,visibility,price,url_key,display_product_options_in,map_price,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,configurable_variations,configurable_variation_labels,associated_skus +Configurable 1-Option 1,,Default,simple,Configurable 1-Option 1,,,,1,Taxable Goods,Not Visible Individually,10,configurable-1-option-1,Block after Info Column,,"attribute_with_option=Option Label,has_options=0,quantity_and_stock_status=In Stock,required_options=0,test_configurable=Option 1",99999,0,0,0,0,1,1,0,0,0,1,,1,1,0,0,1,0,0,0,1,,, +Configurable 1-Option 2,,Default,simple,Configurable 1-Option 2,,,,1,Taxable Goods,Not Visible Individually,10,configurable-1-option-2,Block after Info Column,,"has_options=0,quantity_and_stock_status=In Stock,required_options=0,test_configurable=Option 2",99999,0,0,0,0,1,1,0,0,0,1,,1,1,0,0,1,0,0,0,1,,, +12345,,Default,configurable,12345,,,,1,Taxable Goods,"Catalog, Search",10,12345,Block after Info Column,,"has_options=1,quantity_and_stock_status=In Stock,required_options=0",0,0,0,0,0,1,1,0,0,0,1,,1,0,0,0,1,0,0,0,1,"sku=Configurable 1-Option 1,test_configurable=Option 1|sku=Configurable 1-Option 2,test_configurable=Option 2",test_configurable=test_configurable, diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Variations/Config/MatrixTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Variations/Config/MatrixTest.php index 47bf34efb83ea..8ac94836ac4c4 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Variations/Config/MatrixTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Block/Adminhtml/Product/Edit/Tab/Variations/Config/MatrixTest.php @@ -1,6 +1,6 @@ markTestSkipped('Test skipped due to MAGETWO-45654'); $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $productSku = 'configurable'; /** @var \Magento\ConfigurableProduct\Api\OptionRepositoryInterface $optionRepository */ diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/Configurable/AttributeTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/Configurable/AttributeTest.php index b4b3946e1c582..f674c5031124b 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/Configurable/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/Configurable/AttributeTest.php @@ -1,6 +1,6 @@ prepareOptions( [ [ - 'id' => 1, - 'option_id' => 0, + 'option_id' => null, 'previous_group' => 'text', 'title' => 'Test Field', 'type' => 'field', diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php index cb4320281a075..0e8e61d8dbec0 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php @@ -1,6 +1,6 @@ create(\Magento\Framework\Serialize\Serializer\Json::class); + $product = $this->productRepository->getById(1, true); $attributes = $this->model->getConfigurableAttributesAsArray($product); $attribute = reset($attributes); $optionValueId = $attribute['values'][0]['value_index']; - $product->addCustomOption('attributes', serialize([$attribute['attribute_id'] => $optionValueId])); + $product->addCustomOption('attributes', + $serializer->serialize([$attribute['attribute_id'] => $optionValueId]) + ); + $info = $this->model->getSelectedAttributesInfo($product); - $this->assertEquals([['label' => 'Test Configurable', 'value' => 'Option 1']], $info); + $this->assertEquals('Test Configurable', $info[0]['label']); + $this->assertEquals('Option 1', $info[0]['value']); } /** + * @covers \Magento\ConfigurableProduct\Model\Product\Type\Configurable::getConfigurableAttributes() * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php * @magentoAppIsolation enabled */ public function testGetSelectedAttributesInfoForStore() { + /** @var $serializer \Magento\Framework\Serialize\Serializer\Json */ + $serializer = Bootstrap::getObjectManager()->create(\Magento\Framework\Serialize\Serializer\Json::class); + $attributes = $this->model->getConfigurableAttributesAsArray($this->product); $attribute = reset($attributes); $optionValueId = $attribute['values'][0]['value_index']; - $this->product->addCustomOption('attributes', serialize([$attribute['attribute_id'] => $optionValueId])); + $this->product->addCustomOption( + 'attributes', + $serializer->serialize([$attribute['attribute_id'] => $optionValueId]) + ); $configurableAttr = $this->model->getConfigurableAttributes($this->product); $attribute = $configurableAttr->getFirstItem(); $attribute->getProductAttribute()->setStoreLabel('store label'); $info = $this->model->getSelectedAttributesInfo($this->product); - $this->assertEquals([['label' => 'store label', 'value' => 'Option 1']], $info); + $this->assertEquals('store label', $info[0]['label']); + $this->assertEquals('Option 1', $info[0]['value']); } /** @@ -369,10 +383,8 @@ public function testGetOrderOptions() $result = $this->model->getOrderOptions($product); $this->assertArrayHasKey('info_buyRequest', $result); $this->assertArrayHasKey('attributes_info', $result); - $this->assertEquals( - [['label' => 'Test Configurable', 'value' => 'Option 1']], - $result['attributes_info'] - ); + $this->assertEquals('Test Configurable', $result['attributes_info'][0]['label']); + $this->assertEquals('Option 1', $result['attributes_info'][0]['value']); $this->assertArrayHasKey('product_calculations', $result); $this->assertArrayHasKey('shipment_type', $result); $this->assertEquals( diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/VariationHandlerTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/VariationHandlerTest.php index ce0835b35dbdb..5c9643a6e7876 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/VariationHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/VariationHandlerTest.php @@ -1,6 +1,6 @@ storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); + $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + } + + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetProductFinalPriceIfOneOfChildIsDisabled() + { + /** @var Collection $collection */ + $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) + ->create(); + $configurableProduct = $collection + ->addIdFilter([1]) + ->addMinimalPrice() + ->load() + ->getFirstItem(); + $this->assertEquals(10, $configurableProduct->getMinimalPrice()); + + $childProduct = $this->productRepository->getById(10, false, null, true); + $childProduct->setStatus(Status::STATUS_DISABLED); + // update in global scope + $currentStoreId = $this->storeManager->getStore()->getId(); + $this->storeManager->setCurrentStore(Store::ADMIN_CODE); + $this->productRepository->save($childProduct); + $this->storeManager->setCurrentStore($currentStoreId); + + /** @var Collection $collection */ + $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) + ->create(); + $configurableProduct = $collection + ->addIdFilter([1]) + ->addMinimalPrice() + ->load() + ->getFirstItem(); + $this->assertEquals(20, $configurableProduct->getMinimalPrice()); + } + + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetProductFinalPriceIfOneOfChildIsDisabledPerStore() + { + /** @var Collection $collection */ + $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) + ->create(); + $configurableProduct = $collection + ->addIdFilter([1]) + ->addMinimalPrice() + ->load() + ->getFirstItem(); + $this->assertEquals(10, $configurableProduct->getMinimalPrice()); + + $childProduct = $this->productRepository->getById(10, false, null, true); + $childProduct->setStatus(Status::STATUS_DISABLED); + + // update in default store scope + $currentStoreId = $this->storeManager->getStore()->getId(); + $defaultStore = $this->storeManager->getDefaultStoreView(); + $this->storeManager->setCurrentStore($defaultStore->getId()); + $this->productRepository->save($childProduct); + $this->storeManager->setCurrentStore($currentStoreId); + + /** @var Collection $collection */ + $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) + ->create(); + $configurableProduct = $collection + ->addIdFilter([1]) + ->addMinimalPrice() + ->load() + ->getFirstItem(); + $this->assertEquals(20, $configurableProduct->getMinimalPrice()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php new file mode 100644 index 0000000000000..ed0cca3cebf92 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Pricing/Price/LowestPriceOptionProviderTest.php @@ -0,0 +1,130 @@ +storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); + $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + $this->lowestPriceOptionsProvider = Bootstrap::getObjectManager()->get( + LowestPriceOptionsProviderInterface::class + ); + } + + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetProductsIfOneOfChildIsDisabled() + { + $configurableProduct = $this->productRepository->getById(1, false, null, true); + $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct); + $this->assertCount(1, $lowestPriceChildrenProducts); + $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts); + $this->assertEquals(10, $lowestPriceChildrenProduct->getPrice()); + + // load full aggregation root + $lowestPriceChildProduct = $this->productRepository->get( + $lowestPriceChildrenProduct->getSku(), + false, + null, + true + ); + $lowestPriceChildProduct->setStatus(Status::STATUS_DISABLED); + // update in global scope + $currentStoreId = $this->storeManager->getStore()->getId(); + $this->storeManager->setCurrentStore(Store::ADMIN_CODE); + $this->productRepository->save($lowestPriceChildProduct); + $this->storeManager->setCurrentStore($currentStoreId); + + $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct); + $this->assertCount(1, $lowestPriceChildrenProducts); + $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts); + $this->assertEquals(20, $lowestPriceChildrenProduct->getPrice()); + } + + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetProductsIfOneOfChildIsDisabledPerStore() + { + $configurableProduct = $this->productRepository->getById(1, false, null, true); + $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct); + $this->assertCount(1, $lowestPriceChildrenProducts); + $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts); + $this->assertEquals(10, $lowestPriceChildrenProduct->getPrice()); + + // load full aggregation root + $lowestPriceChildProduct = $this->productRepository->get( + $lowestPriceChildrenProduct->getSku(), + false, + null, + true + ); + $lowestPriceChildProduct->setStatus(Status::STATUS_DISABLED); + // update in default store scope + $currentStoreId = $this->storeManager->getStore()->getId(); + $defaultStore = $this->storeManager->getDefaultStoreView(); + $this->storeManager->setCurrentStore($defaultStore->getId()); + $this->productRepository->save($lowestPriceChildProduct); + $this->storeManager->setCurrentStore($currentStoreId); + + $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct); + $this->assertCount(1, $lowestPriceChildrenProducts); + $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts); + $this->assertEquals(20, $lowestPriceChildrenProduct->getPrice()); + } + + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + */ + public function testGetProductsIfOneOfChildIsOutOfStock() + { + $configurableProduct = $this->productRepository->getById(1, false, null, true); + $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct); + $this->assertCount(1, $lowestPriceChildrenProducts); + $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts); + $this->assertEquals(10, $lowestPriceChildrenProduct->getPrice()); + + // load full aggregation root + $lowestPriceChildProduct = $this->productRepository->get( + $lowestPriceChildrenProduct->getSku(), + false, + null, + true + ); + $stockItem = $lowestPriceChildProduct->getExtensionAttributes()->getStockItem(); + $stockItem->setIsInStock(0); + $this->productRepository->save($lowestPriceChildProduct); + + $lowestPriceChildrenProducts = $this->lowestPriceOptionsProvider->getProducts($configurableProduct); + $this->assertCount(1, $lowestPriceChildrenProducts); + $lowestPriceChildrenProduct = reset($lowestPriceChildrenProducts); + $this->assertEquals(20, $lowestPriceChildrenProduct->getPrice()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProductsTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProductsTest.php new file mode 100644 index 0000000000000..0f23cd2ab40bc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/Data/AssociatedProductsTest.php @@ -0,0 +1,78 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->registry = $this->objectManager->get(\Magento\Framework\Registry::class); + + } + + /** + * @dataProvider getProductMatrixDataProvider + * @param string $interfaceLocale + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @magentoAppArea adminhtml + */ + public function testGetProductMatrix($interfaceLocale) + { + $productSku = 'configurable'; + $associatedProductsData = [ + [10 => '10.000'], + [20 => '20.000'] + ]; + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $this->registry->register('current_product', $productRepository->get($productSku)); + /** @var $store \Magento\Store\Model\Store */ + $store = $this->objectManager->create(\Magento\Store\Model\Store::class); + $store->load('admin'); + $this->registry->register('current_store', $store); + /** @var \Magento\Framework\Locale\ResolverInterface|\PHPUnit_Framework_MockObject_MockObject $localeResolver */ + $localeResolver = $this->getMockBuilder(\Magento\Framework\Locale\ResolverInterface::class) + ->setMethods(['getLocale']) + ->getMockForAbstractClass(); + $localeResolver->expects($this->any())->method('getLocale')->willReturn($interfaceLocale); + $localeCurrency = $this->objectManager->create( + \Magento\Framework\Locale\CurrencyInterface::class, + ['localeResolver' => $localeResolver] + ); + $associatedProducts = $this->objectManager->create( + AssociatedProducts::class, + ['localeCurrency' => $localeCurrency] + ); + foreach ($associatedProducts->getProductMatrix() as $productMatrixId => $productMatrixData) { + $this->assertEquals( + $associatedProductsData[$productMatrixId][$productMatrixData['id']], + $productMatrixData['price'] + ); + } + } + + /** + * @return array + */ + public function getProductMatrixDataProvider() + { + return [ + ['en_US'], + ['zh_Hans_CN'] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php index 2ef7beb59838f..7d349d116b398 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute.php @@ -1,6 +1,6 @@ save($attribute); + + /* Assign attribute to attribute set */ + $installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); } -/* Assign attribute to attribute set */ -$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); $eavConfig->clear(); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute_rollback.php index bd18100f6d97b..2ed4c07efbe39 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute_rollback.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute_rollback.php @@ -1,6 +1,6 @@ reinitialize(); + +require __DIR__ . '/configurable_attribute.php'; + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = Bootstrap::getObjectManager() + ->create(ProductRepositoryInterface::class); + +/** @var $installer CategorySetup */ +$installer = Bootstrap::getObjectManager()->create(CategorySetup::class); + +/* Create simple products per each option value*/ +/** @var AttributeOptionInterface[] $options */ +$options = $attribute->getOptions(); + +$attributeValues = []; +$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default'); +$associatedProductIds = []; +$productIds = [30, 40]; +array_shift($options); //remove the first option which is empty + +foreach ($options as $option) { + /** @var $product Product */ + $product = Bootstrap::getObjectManager()->create(Product::class); + $productId = array_shift($productIds); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setId($productId) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Option' . $option->getLabel()) + ->setSku('simple_' . $productId) + ->setPrice($productId) + ->setTestConfigurable($option->getValue()) + ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]); + + $product = $productRepository->save($product); + + /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */ + $stockItem = Bootstrap::getObjectManager()->create(\Magento\CatalogInventory\Model\Stock\Item::class); + $stockItem->load($productId, 'product_id'); + + if (!$stockItem->getProductId()) { + $stockItem->setProductId($productId); + } + $stockItem->setUseConfigManageStock(1); + $stockItem->setQty(1000); + $stockItem->setIsQtyDecimal(0); + $stockItem->setIsInStock(1); + $stockItem->save(); + + $attributeValues[] = [ + 'label' => 'test', + 'attribute_id' => $attribute->getId(), + 'value_index' => $option->getValue(), + ]; + $associatedProductIds[] = $product->getId(); +} + +/** @var $product Product */ +$product = Bootstrap::getObjectManager()->create(Product::class); + +/** @var Factory $optionsFactory */ +$optionsFactory = Bootstrap::getObjectManager()->create(Factory::class); + +$configurableAttributesData = [ + [ + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'label' => $attribute->getStoreLabel(), + 'position' => '0', + 'values' => $attributeValues, + ], +]; + +$configurableOptions = $optionsFactory->create($configurableAttributesData); + +$extensionConfigurableAttributes = $product->getExtensionAttributes(); +$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions); +$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds); + +$product->setExtensionAttributes($extensionConfigurableAttributes); + +// Remove any previously created product with the same id. +/** @var \Magento\Framework\Registry $registry */ +$registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +try { + $productToDelete = $productRepository->getById(11); + $productRepository->delete($productToDelete); + + /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource */ + $itemResource = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\ResourceModel\Quote\Item::class); + $itemResource->getConnection()->delete( + $itemResource->getMainTable(), + 'product_id = ' . $productToDelete->getId() + ); +} catch (\Exception $e) { + // Nothing to remove +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +$product->setTypeId(Configurable::TYPE_CODE) + ->setId(11) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Product 12345') + ->setSku('12345') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345_rollback.php new file mode 100644 index 0000000000000..459c10f2b58ed --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_12345_rollback.php @@ -0,0 +1,36 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +foreach (['simple_30', 'simple_40', '12345'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + + $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class); + $stockStatus->load($product->getEntityId(), 'product_id'); + $stockStatus->delete(); + + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed + } +} + +require __DIR__ . '/configurable_attribute_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php index 8ba4e3abe21cc..25d58cdaccdde 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php @@ -1,6 +1,6 @@ 1, ] )->setCanSaveCustomOptions(true) - ->setHasOptions(true); + ->setHasOptions(true) + ->setCustomAttribute('test_configurable', 42); $oldOptions = [ [ @@ -104,14 +107,14 @@ 'sort_order' => 0, 'values' => [ [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 1', 'price' => 3, 'price_type' => 'fixed', 'sku' => '3-1-select', ], [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 2', 'price' => 3, 'price_type' => 'fixed', @@ -127,14 +130,14 @@ 'sort_order' => 0, 'values' => [ [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 1', 'price' => 3, 'price_type' => 'fixed', 'sku' => '4-1-radio', ], [ - 'option_type_id' => -1, + 'option_type_id' => null, 'title' => 'Option 2', 'price' => 3, 'price_type' => 'fixed', diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/quote_with_configurable_product.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/quote_with_configurable_product.php index 78f905b199b85..f0110b8a466ee 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/quote_with_configurable_product.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/quote_with_configurable_product.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php b/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php index 69a454997d0ad..ab2d1f73ff837 100644 --- a/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Contact/Controller/IndexTest.php @@ -1,6 +1,6 @@ assertContains("
    assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html); $this->assertContains( - "backend/customer/cart_product_composite_cart/configure/customer_id/" . self::CUSTOMER_ID_VALUE, + 'backend\u002Fcustomer\u002Fcart_product_composite_cart\u002Fconfigure\u002Fcustomer_id\u002F' + . self::CUSTOMER_ID_VALUE, $html ); } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php index b3bd4aa494708..905a507eddc1f 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/CartsTest.php @@ -1,6 +1,6 @@ assertContains("customer_cart_grid1JsObject = new varienGrid(\"customer_cart_grid1\",", $html); - $this->assertContains("backend/customer/cart_product_composite_cart/configure/website_id/1", $html); + $this->assertContains( + 'backend\u002Fcustomer\u002Fcart_product_composite_cart\u002Fconfigure\u002Fwebsite_id\u002F1', + $html + ); } public function testGetHtmlNoCustomer() @@ -85,6 +88,6 @@ public function testGetHtmlNoCustomer() $html ); $this->assertContains("customer_cart_gridJsObject = new varienGrid(\"customer_cart_grid\",", $html); - $this->assertContains("backend/customer/cart_product_composite_cart/configure/key/", $html); + $this->assertContains('backend\u002Fcustomer\u002Fcart_product_composite_cart\u002Fupdate\u002Fkey', $html); } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php index 4b6fc648202bd..e97a5da4f6c68 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php @@ -1,6 +1,6 @@ assertContains('title="Tax/VAT number"', $block->toHtml()); + $this->assertContains('title="Tax/VAT number"', $block->toHtml()); $this->assertNotContains('required', $block->toHtml()); } @@ -44,7 +44,7 @@ public function testToHtmlRequired() \Magento\Customer\Block\Widget\Taxvat::class ); - $this->assertContains('title="Tax/VAT number"', $block->toHtml()); + $this->assertContains('title="Tax/VAT number"', $block->toHtml()); $this->assertContains('required', $block->toHtml()); } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index ca0df844e7e13..eb9c7f063eeca 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -1,6 +1,6 @@ assertContains('
    ', $body); // Verify the password check box is not checked $this->assertContains('', $body); + .'data-role="change-password" value="1" title="Change Password" class="checkbox" />', $body); } /** @@ -477,7 +477,8 @@ public function testChangePasswordEditAction() // Verify the password check box is checked $this->assertContains( '', + . 'data-role="change-password" value="1" title="Change Password" checked="checked" ' + . 'class="checkbox" />', $body ); } @@ -542,7 +543,7 @@ public function testChangePasswordEditPostAction() $this->getRequest() ->setMethod('POST') ->setPostValue([ - 'form_key' => $this->_objectManager->get( + 'form_key' => $this->_objectManager->get( \Magento\Framework\Data\Form\FormKey::class)->getFormKey(), 'firstname' => 'John', 'lastname' => 'Doe', @@ -603,7 +604,7 @@ public function testWrongPasswordEditPostAction() $this->getRequest() ->setMethod('POST') ->setPostValue([ - 'form_key' => $this->_objectManager->get( + 'form_key' => $this->_objectManager->get( \Magento\Framework\Data\Form\FormKey::class)->getFormKey(), 'firstname' => 'John', 'lastname' => 'Doe', @@ -633,7 +634,7 @@ public function testWrongConfirmationEditPostAction() $this->getRequest() ->setMethod('POST') ->setPostValue([ - 'form_key' => $this->_objectManager->get( + 'form_key' => $this->_objectManager->get( \Magento\Framework\Data\Form\FormKey::class)->getFormKey(), 'firstname' => 'John', 'lastname' => 'Doe', diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php index 3a97f7607c0fd..f16910971cc3f 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AddressTest.php @@ -1,6 +1,6 @@ passwordResetRequestEventCreate( + \Magento\Security\Model\PasswordResetRequestEvent::CUSTOMER_PASSWORD_RESET_REQUEST + ); + $this->getRequest()->setPostValue(['customer_id' => '1']); + $this->dispatch('backend/customer/index/resetPassword'); + $this->assertSessionMessages( + $this->equalTo(['The customer will receive an email with a link to reset password.']), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl . 'edit')); + } + + /** + * Checks reset password functionality with default settings, customer and admin reset request events. + * + * @magentoConfigFixture current_store admin/security/limit_password_reset_requests_method 1 + * @magentoConfigFixture current_store admin/security/min_time_between_password_reset_requests 10 + * @magentoConfigFixture current_store contact/email/recipient_email hello@example.com + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testResetPasswordWithSecurityViolationException() + { + $this->passwordResetRequestEventCreate( + \Magento\Security\Model\PasswordResetRequestEvent::CUSTOMER_PASSWORD_RESET_REQUEST + ); + $this->passwordResetRequestEventCreate( + \Magento\Security\Model\PasswordResetRequestEvent::ADMIN_PASSWORD_RESET_REQUEST + ); + $this->getRequest()->setPostValue(['customer_id' => '1']); + $this->dispatch('backend/customer/index/resetPassword'); + $this->assertSessionMessages( + $this->equalTo( + ['Too many password reset requests. Please wait and try again or contact hello@example.com.'] + ), + \Magento\Framework\Message\MessageInterface::TYPE_ERROR + ); + $this->assertRedirect($this->stringStartsWith($this->baseControllerUrl . 'edit')); + } + + /** + * Create and save reset request event with provided request type. + * + * @param int $requestType + */ + private function passwordResetRequestEventCreate($requestType) + { + $passwordResetRequestEventFactory = $this->_objectManager->get( + \Magento\Security\Model\PasswordResetRequestEventFactory::class + ); + $passwordResetRequestEvent = $passwordResetRequestEventFactory->create(); + $passwordResetRequestEvent + ->setRequestType($requestType) + ->setAccountReference('customer@example.com') + ->setCreatedAt(strtotime('now')) + ->setIp('3232249856') + ->save(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php index 1576ff90cb38e..9bd79c6d10298 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php @@ -1,6 +1,6 @@ assertEquals(2, count($addresses)); $updatedAddress = $this->addressRepository->getById(1); $this->assertEquals('update firstname', $updatedAddress->getFirstname()); + $this->assertTrue($updatedAddress->isDefaultBilling()); + $this->assertEquals($updatedAddress->getId(), $customer->getDefaultBilling()); $newAddress = $this->accountManagement->getDefaultShippingAddress($customerId); $this->assertEquals('new firstname', $newAddress->getFirstname()); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AjaxLoginTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AjaxLoginTest.php index 4e44bdbf63bd6..5e7b4ab58db02 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AjaxLoginTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AjaxLoginTest.php @@ -1,6 +1,6 @@ '"section<invalid" section source is not supported', + ]; + $this->dispatch('/customer/section/load/?sections=sectiongetResponse()->getBody()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Customer/Helper/AddressTest.php b/dev/tests/integration/testsuite/Magento/Customer/Helper/AddressTest.php index 0e0d5bc7c2a06..4d35b698f18a4 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Helper/AddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Helper/AddressTest.php @@ -1,6 +1,6 @@ get( \Magento\Customer\Model\Config\Source\Group\Multiselect::class ); + + $options = $multiselect->toOptionArray(); + $optionsToCompare = []; + foreach ($options as $option) { + if (is_array($option['value'])) { + $optionsToCompare = array_merge($optionsToCompare, $option['value']); + } else { + $optionsToCompare[] = $option; + } + } + sort($optionsToCompare); $this->assertEquals( [ ['value' => 1, 'label' => 'General'], ['value' => 2, 'label' => 'Wholesale'], ['value' => 3, 'label' => 'Retailer'], ], - $multiselect->toOptionArray() + $optionsToCompare ); } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/Config/Source/GroupTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/Config/Source/GroupTest.php index b4674c7b6aae3..35fdf30e5b95b 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/Config/Source/GroupTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/Config/Source/GroupTest.php @@ -1,6 +1,6 @@ get(\Magento\Customer\Model\Config\Source\Group::class); - $this->assertEquals( - [ - ['value' => '', 'label' => '-- Please Select --'], - ['value' => 1, 'label' => 'General'], - ['value' => 2, 'label' => 'Wholesale'], - ['value' => 3, 'label' => 'Retailer'], - ], - $group->toOptionArray() + $options = $group->toOptionArray(); + $this->assertContainsOptionRecursive('', '-- Please Select --', $options); + } + + private function assertContainsOptionRecursive($expectedValue, $expectedLabel, array $values) + { + $this->assertTrue( + $this->hasOptionLabelRecursive($expectedValue, $expectedLabel, $values), + 'Label ' . $expectedLabel . ' not found' ); } + + private function hasOptionLabelRecursive($value, $label, array $values) + { + $hasLabel = false; + foreach ($values as $option) { + $this->assertArrayHasKey('label', $option); + $this->assertArrayHasKey('value', $option); + if (strpos((string)$option['label'], (string)$label) !== false) { + $this->assertEquals($value, $option['value']); + $hasLabel = true; + break; + } elseif (is_array($option['value'])) { + $hasLabel |= $this->hasOptionLabelRecursive($value, $label, $option['value']); + } + } + + return (bool)$hasLabel; + } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php index e188306db627f..c22a45cd906f2 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php @@ -1,6 +1,6 @@ 1, + "website_id" => 1, + "email" => "roni_cost@example.com", + "firstname" => "1111", + "lastname" => "Boss", + "middlename" => null, + "gender" => 0 + ]; + + $customerEntity = $this->customerFactory->create(['data' => $customerData]); + + $customer = $this->customerRepository->getById($customerId); + $oldDefaultBilling = $customer->getDefaultBilling(); + $oldDefaultShipping = $customer->getDefaultShipping(); + + $savedCustomer = $this->customerRepository->save($customerEntity); + + $this->assertEquals( + $savedCustomer->getDefaultBilling(), + $oldDefaultBilling, + 'Default billing shoud not be overridden' + ); + + $this->assertEquals( + $savedCustomer->getDefaultShipping(), + $oldDefaultShipping, + 'Default shipping shoud not be overridden' + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php index d18e52be749af..b3054e8c864c3 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php @@ -2,7 +2,7 @@ /** * \Magento\Customer\Model\ResourceModel\Group\Grid\ServiceCollection * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Model\ResourceModel\Group\Grid; diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/GroupRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/GroupRepositoryTest.php index b46e2e7d9b219..036b1ab968ec3 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/GroupRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/ResourceModel/GroupRepositoryTest.php @@ -1,6 +1,6 @@ create( diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id.php index 305a6e699125f..2a39c0a477121 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id.php @@ -1,6 +1,8 @@ setName('new Website')->setCode('newwebsite')->save(); $websiteId = $website->getId(); - -$customer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( +$storeManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Store\Model\StoreManager::class); +$storeManager->reinitStores(); +$customer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Customer\Model\Customer::class); /** @var Magento\Customer\Model\Customer $customer */ $customer->setWebsiteId( @@ -47,7 +51,7 @@ $customer->isObjectNew(true); /** @var \Magento\Customer\Model\Address $addressOne */ -$addressOne = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( +$addressOne = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Customer\Model\Address::class); $addressOneData = [ 'firstname' => 'Firstname', @@ -63,7 +67,7 @@ $customer->addAddress($addressOne); /** @var \Magento\Customer\Model\Address $addressTwo */ -$addressTwo = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( +$addressTwo = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Customer\Model\Address::class); $addressTwoData = [ 'firstname' => 'test firstname', @@ -79,7 +83,7 @@ $customer->addAddress($addressTwo); /** @var \Magento\Customer\Model\Address $addressThree */ -$addressThree = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( +$addressThree = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Customer\Model\Address::class); $addressThreeData = [ 'firstname' => 'removed firstname', diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id_rollback.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id_rollback.php index 8a16528fec6ba..face559a70acc 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_non_default_website_id_rollback.php @@ -1,6 +1,6 @@ create( diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_sample.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_sample.php index 62b9d76da1cad..340d6f594ef83 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_sample.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_sample.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/import_export/customer.php b/dev/tests/integration/testsuite/Magento/Customer/_files/import_export/customer.php index ebf8219b080ce..4d7ddd795d5ed 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/import_export/customer.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/import_export/customer.php @@ -1,6 +1,6 @@ create( diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/quote.php b/dev/tests/integration/testsuite/Magento/Customer/_files/quote.php index 8791c1a6fc70b..70a70bd6868e5 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/quote.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/quote.php @@ -1,6 +1,6 @@ create( diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/two_customers.php b/dev/tests/integration/testsuite/Magento/Customer/_files/two_customers.php index 23f102fa607dc..3f97792b90a4f 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/_files/two_customers.php +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/two_customers.php @@ -2,7 +2,7 @@ /** * Fixture for Customer List method. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Customer/etc/extension_attributes.xml b/dev/tests/integration/testsuite/Magento/Customer/etc/extension_attributes.xml index 0da9345b64164..f726676ee7204 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/etc/extension_attributes.xml +++ b/dev/tests/integration/testsuite/Magento/Customer/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Export/AddressTest.php b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Export/AddressTest.php index f28fd6328f379..dc49beccba474 100644 --- a/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Export/AddressTest.php +++ b/dev/tests/integration/testsuite/Magento/CustomerImportExport/Model/Export/AddressTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->reader = $this->objectManager->get(DeploymentConfig\Reader::class); + } + + /** + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Deploy/_files/config_data.php + */ + public function testExecute() + { + $this->objectManager->configure([ + \Magento\Config\Model\Config\Export\ExcludeList::class => [ + 'arguments' => [ + 'configs' => [ + 'web/test/test_value_1' => '', + 'web/test/test_value_2' => '', + 'web/test/test_sensitive' => '1', + ], + ], + ], + ]); + + $comment = 'The configuration file doesn\'t contain sensitive data for security reasons. ' + . 'Sensitive data can be stored in the following environment variables:' + . "\nCONFIG__DEFAULT__WEB__TEST__TEST_SENSITIVE for web/test/test_sensitive"; + $outputMock = $this->getMock(OutputInterface::class); + $outputMock->expects($this->at(0)) + ->method('writeln') + ->with(['system' => $comment]); + $outputMock->expects($this->at(1)) + ->method('writeln') + ->with('Done.'); + + /** @var ApplicationDumpCommand command */ + $command = $this->objectManager->create(ApplicationDumpCommand::class); + $command->run($this->getMock(InputInterface::class), $outputMock); + + $config = $this->reader->loadConfigFile(ConfigFilePool::APP_CONFIG, $this->getFileName()); + + $this->validateSystemSection($config); + $this->validateThemesSection($config); + } + + /** + * Validates 'system' section in configuration data. + * + * @param array $config The configuration array + * @return void + */ + private function validateSystemSection(array $config) + { + $this->assertArrayHasKey( + 'test_value_1', + $config['system']['default']['web']['test'] + ); + $this->assertArrayHasKey( + 'test_value_2', + $config['system']['default']['web']['test'] + ); + $this->assertArrayNotHasKey( + 'test_sensitive', + $config['system']['default']['web']['test'] + ); + } + + /** + * Validates 'themes' section in configuration data. + * + * @param array $config The configuration array + * @return void + */ + private function validateThemesSection(array $config) + { + $this->assertEquals( + [ + 'parent_id' => null, + 'theme_path' => 'Magento/backend', + 'theme_title' => 'Magento 2 backend', + 'is_featured' => '0', + 'area' => 'adminhtml', + 'type' => '0', + 'code' => 'Magento/backend', + ], + $config['themes']['Magento/backend'] + ); + $this->assertEquals( + [ + 'parent_id' => null, + 'theme_path' => 'Magento/blank', + 'theme_title' => 'Magento Blank', + 'is_featured' => '0', + 'area' => 'frontend', + 'type' => '0', + 'code' => 'Magento/blank', + ], + $config['themes']['Magento/blank'] + ); + $this->assertEquals( + [ + 'parent_id' => 'Magento/blank', + 'theme_path' => 'Magento/luma', + 'theme_title' => 'Magento Luma', + 'is_featured' => '0', + 'area' => 'frontend', + 'type' => '0', + 'code' => 'Magento/luma', + ], + $config['themes']['Magento/luma'] + ); + } + + public function tearDown() + { + $file = $this->getFileName(); + /** @var DirectoryList $dirList */ + $dirList = $this->objectManager->get(DirectoryList::class); + $path = $dirList->getPath(DirectoryList::CONFIG); + $driverPool = $this->objectManager->get(DriverPool::class); + $fileDriver = $driverPool->getDriver(DriverPool::FILE); + if ($fileDriver->isExists($path . '/' . $file)) { + unlink($path . '/' . $file); + } + /** @var DeploymentConfig $deploymentConfig */ + $deploymentConfig = $this->objectManager->get(DeploymentConfig::class); + $deploymentConfig->resetData(); + } + + /** + * @return string + */ + private function getFileName() + { + /** @var ConfigFilePool $configFilePool */ + $configFilePool = $this->objectManager->get(ConfigFilePool::class); + $filePool = $configFilePool->getInitialFilePools(); + + return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommandTest.php new file mode 100644 index 0000000000000..1b0fe2de866e8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/SensitiveConfigSetCommandTest.php @@ -0,0 +1,291 @@ +objectManager = Bootstrap::getObjectManager(); + $this->reader = $this->objectManager->get(Reader::class); + $this->configFilePool = $this->objectManager->get(ConfigFilePool::class); + $this->config = $this->loadConfig(); + $this->filesystem = $this->objectManager->get(Filesystem::class); + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile( + $this->getFileName(), + file_get_contents(__DIR__ . '/../../../_files/_config.local.php') + ); + } + + /** + * @param $scope + * @param $scopeCode + * @param callable $assertCallback + * @magentoDataFixture Magento/Store/_files/website.php + * @magentoDbIsolation enabled + * @dataProvider testExecuteDataProvider + */ + public function testExecute($scope, $scopeCode, callable $assertCallback) + { + $outputMock = $this->getMock(OutputInterface::class); + $outputMock->expects($this->at(0)) + ->method('writeln') + ->with('Configuration value saved in app/etc/config.php'); + + $inputMock = $this->getMock(InputInterface::class); + $inputMock->expects($this->exactly(2)) + ->method('getArgument') + ->withConsecutive( + [SensitiveConfigSetCommand::INPUT_ARGUMENT_PATH], + [SensitiveConfigSetCommand::INPUT_ARGUMENT_VALUE] + ) + ->willReturnOnConsecutiveCalls( + 'some/config/path_two', + 'sensitiveValue' + ); + $inputMock->expects($this->exactly(3)) + ->method('getOption') + ->withConsecutive( + [SensitiveConfigSetCommand::INPUT_OPTION_SCOPE], + [SensitiveConfigSetCommand::INPUT_OPTION_SCOPE_CODE], + [SensitiveConfigSetCommand::INPUT_OPTION_INTERACTIVE] + ) + ->willReturnOnConsecutiveCalls( + $scope, + $scopeCode, + null + ); + + /** @var SensitiveConfigSetCommand command */ + $command = $this->objectManager->create(SensitiveConfigSetCommand::class); + $command->run($inputMock, $outputMock); + + $config = $this->loadConfig(); + + $assertCallback($config); + } + + public function testExecuteDataProvider() + { + return [ + [ + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + function (array $config) { + $this->assertTrue(isset($config['system']['default']['some']['config']['path_two'])); + $this->assertEquals( + 'sensitiveValue', + $config['system']['default']['some']['config']['path_two'] + ); + } + ], + [ + 'website', + 'test', + function (array $config) { + $this->assertTrue(isset($config['system']['website']['test']['some']['config']['path_two'])); + $this->assertEquals( + 'sensitiveValue', + $config['system']['website']['test']['some']['config']['path_two'] + ); + } + ] + ]; + } + + /** + * @param $scope + * @param $scopeCode + * @param callable $assertCallback + * @magentoDataFixture Magento/Store/_files/website.php + * @magentoDbIsolation enabled + * @dataProvider testExecuteInteractiveDataProvider + */ + public function testExecuteInteractive($scope, $scopeCode, callable $assertCallback) + { + $inputMock = $this->getMock(InputInterface::class); + $outputMock = $this->getMock(OutputInterface::class); + $outputMock->expects($this->at(0)) + ->method('writeln') + ->with('Please set configuration values or skip them by pressing [Enter]:'); + $outputMock->expects($this->at(1)) + ->method('writeln') + ->with('Configuration values saved in app/etc/config.php'); + $inputMock->expects($this->exactly(3)) + ->method('getOption') + ->withConsecutive( + [SensitiveConfigSetCommand::INPUT_OPTION_SCOPE], + [SensitiveConfigSetCommand::INPUT_OPTION_SCOPE_CODE], + [SensitiveConfigSetCommand::INPUT_OPTION_INTERACTIVE] + ) + ->willReturnOnConsecutiveCalls( + $scope, + $scopeCode, + true + ); + + $questionHelperMock = $this->getMock(QuestionHelper::class); + $questionHelperMock->expects($this->exactly(3)) + ->method('ask') + ->willReturn('sensitiveValue'); + + $interactiveCollectorMock = $this->objectManager->create( + InteractiveCollector::class, + [ + 'questionHelper' => $questionHelperMock + ] + ); + $collectorFactoryMock = $this->getMockBuilder(CollectorFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $collectorFactoryMock->expects($this->once()) + ->method('create') + ->with(CollectorFactory::TYPE_INTERACTIVE) + ->willReturn($interactiveCollectorMock); + + /** @var SensitiveConfigSetCommand command */ + $command = $this->objectManager->create( + SensitiveConfigSetCommand::class, + [ + 'collectorFactory' => $collectorFactoryMock + ] + ); + $command->run($inputMock, $outputMock); + + $config = $this->loadConfig(); + + $assertCallback($config); + } + + public function testExecuteInteractiveDataProvider() + { + return [ + [ + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + function (array $config) { + $this->assertTrue(isset($config['system']['default']['some']['config']['path_one'])); + $this->assertTrue(isset($config['system']['default']['some']['config']['path_two'])); + $this->assertTrue(isset($config['system']['default']['some']['config']['path_three'])); + $this->assertEquals( + 'sensitiveValue', + $config['system']['default']['some']['config']['path_one'] + ); + $this->assertEquals( + 'sensitiveValue', + $config['system']['default']['some']['config']['path_two'] + ); + $this->assertEquals( + 'sensitiveValue', + $config['system']['default']['some']['config']['path_three'] + ); + } + ], + [ + 'website', + 'test', + function (array $config) { + $this->assertTrue(isset($config['system']['website']['test']['some']['config']['path_one'])); + $this->assertTrue(isset($config['system']['website']['test']['some']['config']['path_two'])); + $this->assertTrue(isset($config['system']['website']['test']['some']['config']['path_three'])); + $this->assertEquals( + 'sensitiveValue', + $config['system']['website']['test']['some']['config']['path_one'] + ); + $this->assertEquals( + 'sensitiveValue', + $config['system']['website']['test']['some']['config']['path_two'] + ); + $this->assertEquals( + 'sensitiveValue', + $config['system']['website']['test']['some']['config']['path_three'] + ); + } + ] + ]; + } + + public function tearDown() + { + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->delete( + $this->getFileName() + ); + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile( + $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG), + "objectManager->get(Writer::class); + $writer->saveConfig([ConfigFilePool::APP_CONFIG => $this->config]); + } + + /** + * @return string + */ + private function getFileName() + { + /** @var ConfigFilePool $configFilePool */ + $configFilePool = $this->objectManager->get(ConfigFilePool::class); + $filePool = $configFilePool->getInitialFilePools(); + + return $filePool[ConfigFilePool::LOCAL][ConfigFilePool::APP_CONFIG]; + } + + /** + * @return array + */ + private function loadConfig() + { + return $this->reader->loadConfigFile( + ConfigFilePool::APP_CONFIG, + $this->configFilePool->getPath(ConfigFilePool::APP_CONFIG), + true + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Deploy/_files/_config.local.php b/dev/tests/integration/testsuite/Magento/Deploy/_files/_config.local.php new file mode 100644 index 0000000000000..ae4630b1a2b07 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Deploy/_files/_config.local.php @@ -0,0 +1,23 @@ + [ + 'websites' => [] + ], + /** + * The configuration file doesn't contain sensitive data for security reasons. + * Sensitive data can be stored in the following environment variables: + * CONFIG__DEFAULT__SOME__CONFIG__PATH_ONE for some/config/path_one + * CONFIG__DEFAULT__SOME__CONFIG__PATH_TWO for some/config/path_two + * CONFIG__DEFAULT__SOME__CONFIG__PATH_THREE for some/config/path_three + */ + 'system' => [ + 'default' => [ + 'web' => [], + 'general' => [] + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php new file mode 100644 index 0000000000000..576cf7ea43887 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Deploy/_files/config_data.php @@ -0,0 +1,33 @@ + [ + '' => [ + 'web/test/test_value_1' => 'http://local2.test/', + 'web/test/test_value_2' => 5, + 'web/test/test_sensitive' => 10, + ] + ], +]; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$configFactory = $objectManager->create(\Magento\Config\Model\Config\Factory::class); + +foreach ($configData as $scope => $data) { + foreach ($data as $scopeCode => $scopeData) { + foreach ($scopeData as $path => $value) { + $config = $configFactory->create(); + $config->setCope($scope); + + if ($scopeCode) { + $config->setScopeCode($scopeCode); + } + + $config->setDataByPath($path, $value); + $config->save(); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Developer/Console/Command/SourceThemeDeployCommandTest.php b/dev/tests/integration/testsuite/Magento/Developer/Console/Command/SourceThemeDeployCommandTest.php index 1090edd350e96..d80977f82cd34 100644 --- a/dev/tests/integration/testsuite/Magento/Developer/Console/Command/SourceThemeDeployCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Developer/Console/Command/SourceThemeDeployCommandTest.php @@ -1,6 +1,6 @@ block = $objectManager->get(\Magento\Directory\Block\Data::class); + } + + public function testGetCountryHtmlSelect() + { + CacheCleaner::cleanAll(); + $result = $this->block->getCountryHtmlSelect(); + $resultTwo = $this->block->getCountryHtmlSelect(); + $this->assertEquals($result, $resultTwo); + } + + public function testGetRegionHtmlSelect() + { + CacheCleaner::cleanAll(); + $result = $this->block->getRegionHtmlSelect(); + $resultTwo = $this->block->getRegionHtmlSelect(); + $this->assertEquals($result, $resultTwo); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Directory/Helper/DataTest.php b/dev/tests/integration/testsuite/Magento/Directory/Helper/DataTest.php index 5d0c91e8230ee..9b4c55723c791 100644 --- a/dev/tests/integration/testsuite/Magento/Directory/Helper/DataTest.php +++ b/dev/tests/integration/testsuite/Magento/Directory/Helper/DataTest.php @@ -1,6 +1,6 @@ reader = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Directory\Model\Country\Postcode\Config\Reader::class + ); + } + + public function testRead() + { + $result = $this->reader->read(); + + $this->assertArrayHasKey('NL', $result); + $this->assertArrayHasKey('pattern_1', $result['NL']); + $this->assertArrayHasKey('pattern_2', $result['NL']); + + $this->assertEquals('test1', $result['NL']['pattern_1']['example']); + $this->assertEquals('^[0-9]{4}\s[a-zA-Z]{2}$', $result['NL']['pattern_1']['pattern']); + + $this->assertEquals('test2', $result['NL']['pattern_2']['example']); + $this->assertEquals('^[0-5]{4}[a-z]{2}$', $result['NL']['pattern_2']['pattern']); + + $this->assertArrayHasKey('NL_NEW', $result); + $this->assertArrayHasKey('pattern_1', $result['NL_NEW']); + + $this->assertEquals('test1', $result['NL_NEW']['pattern_1']['example']); + $this->assertEquals('^[0-2]{4}[A-Z]{2}$', $result['NL_NEW']['pattern_1']['pattern']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php index bb9c53fa1b29d..ea4e6aaf38905 100644 --- a/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php +++ b/dev/tests/integration/testsuite/Magento/Directory/Model/Country/Postcode/ValidatorTest.php @@ -1,6 +1,6 @@ markTestSkipped('http://www.webservicex.net is unavailable '); } diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/LinksTest.php b/dev/tests/integration/testsuite/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/LinksTest.php index a453a87c0a404..9758440a1029c 100644 --- a/dev/tests/integration/testsuite/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/LinksTest.php +++ b/dev/tests/integration/testsuite/Magento/Downloadable/Block/Adminhtml/Catalog/Product/Edit/Tab/Downloadable/LinksTest.php @@ -1,6 +1,6 @@ _model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->_model = $this->objectManager->create( \Magento\Downloadable\Model\Product\Type::class ); } @@ -216,4 +222,37 @@ public function testSaveTypeSpecificData() $this->assertEquals($value, $sample[$key]); } } + + /** + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php + * @covers \Magento\Downloadable\Model\Product\Type::checkProductBuyState() + */ + public function testCheckProductBuyState() + { + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository =$this->objectManager->create( + \Magento\Catalog\Api\ProductRepositoryInterface::class + ); + $product = $productRepository->get('downloadable-product'); + $product->setLinksPurchasedSeparately(false); + $productRepository->save($product); + /** @var \Magento\Quote\Model\Quote\Item\Option $option */ + $option = $this->objectManager->create( + \Magento\Quote\Model\Quote\Item\Option::class, + ['data' => ['code' => 'info_buyRequest', 'value' => '{"qty":23}']] + ); + $option->setProduct($product); + $product->setCustomOptions(['info_buyRequest' => $option]); + + $this->_model->checkProductBuyState($product); + $linksFactory = $this->objectManager + ->get(\Magento\Downloadable\Model\ResourceModel\Link\CollectionFactory::class); + $allLinksIds = $linksFactory->create()->addProductToFilter($product->getEntityId())->getAllIds(); + $this->assertEquals( + '{"qty":23,"links":["' . implode('","', $allLinksIds). '"]}', + $product->getCustomOption('info_buyRequest')->getValue() + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/order_item_with_downloadable_and_options.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/order_item_with_downloadable_and_options.php index 1c72bc4373cab..f6e8ae1fd6a6d 100644 --- a/dev/tests/integration/testsuite/Magento/Downloadable/_files/order_item_with_downloadable_and_options.php +++ b/dev/tests/integration/testsuite/Magento/Downloadable/_files/order_item_with_downloadable_and_options.php @@ -1,6 +1,6 @@ create( + \Magento\Sales\Model\Order\Address::class, + [ + 'data' => [ + 'firstname' => 'guest', + 'lastname' => 'guest', + 'email' => 'customer@example.com', + 'street' => 'street', + 'city' => 'Los Angeles', + 'region' => 'CA', + 'postcode' => '1', + 'country_id' => 'US', + 'telephone' => '1', + ] + ] +); +$billingAddress->setAddressType('billing'); + +$payment = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Sales\Model\Order\Payment::class); +$payment->setMethod('checkmo'); + +$orderItem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Sales\Model\Order\Item::class); +$orderItem->setProductId( + 1 +)->setProductType( + \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE +)->setBasePrice( + 100 +)->setQtyOrdered( + 1 +); +$orderItem->setProductOptions(['additional_options' => ['additional_option_key' => 'additional_option_value']]); + +$order = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class); +$order->setCustomerEmail('mail@to.co') + ->addItem( + $orderItem +)->setIncrementId( + '100000001' +)->setCustomerIsGuest( + true +)->setStoreId( + 1 +)->setEmailSent( + 1 +)->setBillingAddress( + $billingAddress +)->setPayment( + $payment +); +$order->save(); diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable.php b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable.php index b7c2ce6904a9a..d9e3b0000c409 100644 --- a/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable.php +++ b/dev/tests/integration/testsuite/Magento/Downloadable/_files/product_downloadable.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/DownloadableTest.php b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/DownloadableTest.php index 3a9bee9f8aad2..58bc436c7d82d 100644 --- a/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/DownloadableTest.php +++ b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/DownloadableTest.php @@ -1,6 +1,6 @@ markTestSkipped('Uncomment after MAGETWO-49467 resolved'); + $this->markTestSkipped('Uncomment after MAGETWO-38240 resolved'); } /** @@ -56,11 +56,11 @@ public function testExport($fixtures, $skus, $skippedAttributes = [], $rollbackF * @dataProvider exportImportDataProvider * @SuppressWarnings(PHPMD.UnusedFormalParameter) * - * @todo remove after MAGETWO-49467 resolved + * @todo remove after MAGETWO-38240 resolved */ public function testImportDelete($fixtures, $skus, $skippedAttributes = [], $rollbackFixtures = []) { - $this->markTestSkipped('Uncomment after MAGETWO-49467 resolved'); + $this->markTestSkipped('Uncomment after MAGETWO-38240 resolved'); } /** @@ -72,12 +72,13 @@ public function testImportDelete($fixtures, $skus, $skippedAttributes = [], $rol * @param string[] $skus * @param string[] $skippedAttributes * @dataProvider importReplaceDataProvider + * @SuppressWarnings(PHPMD.UnusedFormalParameter) * - * @todo remove after MAGETWO-49467 resolved + * @todo remove after MAGETWO-38240 resolved */ public function testImportReplace($fixtures, $skus, $skippedAttributes = [], $rollbackFixtures = []) { - $this->markTestSkipped('Uncomment after MAGETWO-49467 resolved'); + $this->markTestSkipped('Uncomment after MAGETWO-38240 resolved'); } /** diff --git a/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/Product/Type/DownloadableTest.php b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/Product/Type/DownloadableTest.php index 8db369facf97f..5d0a4399b0546 100644 --- a/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/Product/Type/DownloadableTest.php +++ b/dev/tests/integration/testsuite/Magento/DownloadableImportExport/Model/Import/Product/Type/DownloadableTest.php @@ -1,13 +1,11 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $this->objectManager->create(\Magento\Eav\Api\AttributeManagementInterface::class); + } + + /** + * Verify that collection in service used correctly + */ + public function testGetList() + { + $productAttributeSetId = $this->getAttributeSetId( + \Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE + ); + $productAttributes = $this->model->getAttributes( + \Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE, + $productAttributeSetId + ); + // Verify that result contains only product attributes + $this->verifyAttributeSetIds($productAttributes, $productAttributeSetId); + + $categoryAttributeSetId = $this->getAttributeSetId( + \Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE + ); + $categoryAttributes = $this->model->getAttributes( + \Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE, + $categoryAttributeSetId + ); + // Verify that result contains only category attributes + $this->verifyAttributeSetIds($categoryAttributes, $categoryAttributeSetId); + } + + /** + * @param string $entityTypeCode + * @return int + */ + private function getAttributeSetId($entityTypeCode) + { + /** @var \Magento\Eav\Model\Config $eavConfig */ + $eavConfig = $this->objectManager->create(\Magento\Eav\Model\Config::class); + return $eavConfig->getEntityType($entityTypeCode)->getDefaultAttributeSetId(); + } + + /** + * @param array $items + * @param string $attributeSetId + * @return void + */ + private function verifyAttributeSetIds(array $items, $attributeSetId) + { + /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $item */ + foreach ($items as $item) { + $this->assertEquals($attributeSetId, $item->getAttributeSetId()); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/AttributeRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/AttributeRepositoryTest.php index 8c2052183cd82..b57244ccb091d 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/AttributeRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/AttributeRepositoryTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->config = $this->objectManager->get(Config::class); + } + + public function testGetEntityAttributeCodes() + { + $entityType = 'catalog_product'; + CacheCleaner::cleanAll(); + $this->assertEquals( + $this->config->getEntityAttributeCodes($entityType), + $this->config->getEntityAttributeCodes($entityType) + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php index 6ae061c35f020..c3028855c540b 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/Entity/Attribute/CollectionTest.php @@ -1,6 +1,6 @@ create(\Magento\Catalog\Model\Product::class); + $entity->setStoreId(0); + $entity->load(1); + $entity->setData($code, $snapshotValue); + $entity->save(); + } + + $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $entity->setStoreId(0); + $entity->load(1); + + $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class); + $entityData = array_merge($entity->getData(), [$code => $newValue]); + $updateHandler->execute(\Magento\Catalog\Api\Data\ProductInterface::class, $entityData); + + $resultEntity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $resultEntity->setStoreId(0); + $resultEntity->load(1); + + $this->assertSame($expected, $resultEntity->getData($code)); + } + + /** + * @covers \Magento\Eav\Model\ResourceModel\UpdateHandlerTest::execute + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Store/_files/second_store.php + * @dataProvider getCustomStoreDataProvider + * @param $code + * @param $snapshotValue + * @param $newValue + * @param $expected + */ + public function testExecuteProcessForCustomStore($code, $snapshotValue, $newValue, $expected) + { + $store = Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); + $store->load('fixture_second_store', 'code'); + + Bootstrap::getObjectManager() + ->create(\Magento\CatalogSearch\Model\Indexer\Fulltext\Processor::class) + ->reindexAll(); + + if ($snapshotValue !== '-') { + $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $entity->setStoreId($store->getId()); + $entity->load(1); + $entity->setData($code, $snapshotValue); + $entity->save(); + } + + $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $entity->setStoreId($store->getId()); + $entity->load(1); + + $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class); + $entityData = array_merge($entity->getData(), [$code => $newValue]); + $updateHandler->execute(\Magento\Catalog\Api\Data\ProductInterface::class, $entityData); + + $resultEntity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $resultEntity->setStoreId($store->getId()); + $resultEntity->load(1); + + $this->assertSame($expected, $resultEntity->getData($code)); + } + + /** + * @covers \Magento\Eav\Model\ResourceModel\UpdateHandlerTest::execute + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Catalog/_files/dropdown_attribute.php + * @magentoDataFixture Magento/Store/_files/second_store.php + * @dataProvider getCustomAttributeDataProvider + * @param $code + * @param $defaultStoreValue + * @param $snapshotValue + * @param $newValue + * @param $expected + */ + public function testExecuteProcessForCustomAttributeInCustomStore( + $code, + $defaultStoreValue, + $snapshotValue, + $newValue, + $expected + ) { + $store = Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); + $store->load('fixture_second_store', 'code'); + + Bootstrap::getObjectManager() + ->create(\Magento\CatalogSearch\Model\Indexer\Fulltext\Processor::class) + ->reindexAll(); + + $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class + ); + $attribute->loadByCode(4, $code); + + $options = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class + ); + $options->setAttributeFilter($attribute->getId()); + $optionIds = $options->getAllIds(); + + $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $entity->setStoreId(0); + $entity->load(1); + $entity->setData($code, $optionIds[$defaultStoreValue]); + $entity->save(); + + if ($snapshotValue !== '-') { + /** @var $options \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection */ + $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $entity->setStoreId($store->getId()); + $entity->load(1); + + if ($snapshotValue) { + $snapshotValue = $optionIds[$snapshotValue]; + } + + $entity->setData($code, $snapshotValue); + $entity->save(); + } + + $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $entity->setStoreId($store->getId()); + $entity->load(1); + + $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class); + + if ($newValue) { + $newValue = $optionIds[$newValue]; + } + + $entityData = array_merge($entity->getData(), [$code => $newValue]); + $updateHandler->execute(\Magento\Catalog\Api\Data\ProductInterface::class, $entityData); + + $resultEntity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); + $resultEntity->setStoreId($store->getId()); + $resultEntity->load(1); + + if ($expected !== null) { + $expected = $optionIds[$expected]; + } + + $this->assertSame($expected, $resultEntity->getData($code)); + } + + /** + * @return array + */ + public function getAllStoresDataProvider() + { + return [ + ['description', '', 'not_empty_value', 'not_empty_value'], //0 + ['description', '', '', null], //1 + ['description', '', null, null], //2 + ['description', '', false, null], //3 + + ['description', 'not_empty_value', 'not_empty_value2', 'not_empty_value2'], //4 + ['description', 'not_empty_value', '', null], //5 + ['description', 'not_empty_value', null, null], //6 + ['description', 'not_empty_value', false, null], //7 + + ['description', null, 'not_empty_value', 'not_empty_value'], //8 + ['description', null, '', null], //9 + ['description', null, false, null], //10 + + ['description', false, 'not_empty_value', 'not_empty_value'], //11 + ['description', false, '', null], //12 + ['description', false, null, null], //13 + ]; + } + + /** + * @return array + */ + public function getCustomStoreDataProvider() + { + return [ + ['description', '', 'not_empty_value', 'not_empty_value'], //0 + ['description', '', '', null], //1 + ['description', '', null, 'Description with html tag'], //2 + ['description', '', false, 'Description with html tag'], //3 + + ['description', 'not_empty_value', 'not_empty_value2', 'not_empty_value2'], //4 + ['description', 'not_empty_value', '', null], //5 + ['description', 'not_empty_value', null, 'Description with html tag'], //6 + ['description', 'not_empty_value', false, 'Description with html tag'], //7 + + ['description', null, 'not_empty_value', 'not_empty_value'], //8 + ['description', null, '', null], //9 + ['description', null, false, 'Description with html tag'], //10 + + ['description', false, 'not_empty_value', 'not_empty_value'], //11 + ['description', false, '', null], //12 + ['description', false, null, 'Description with html tag'], //13 + ]; + } + + /** + * @return array + */ + public function getCustomAttributeDataProvider() + { + return [ + ['dropdown_attribute', 0, '', 1, 1], //0 + ['dropdown_attribute', 0, '', '', null], //1 + ['dropdown_attribute', 0, '', null, 0], //2 + ['dropdown_attribute', 0, '', false, 0], //3 + + ['dropdown_attribute', 0, 1, 2, 2], //4 + ['dropdown_attribute', 0, 1, '', null], //5 + ['dropdown_attribute', 0, 1, null, 0], //6 + ['dropdown_attribute', 0, 1, false, 0], //7 + + ['dropdown_attribute', 0, null, 1, 1], //8 + ['dropdown_attribute', 0, null, '', null], //9 + ['dropdown_attribute', 0, null, false, 0], //10 + + ['dropdown_attribute', 0, false, 1, 1], //11 + ['dropdown_attribute', 0, false, '', null], //12 + ['dropdown_attribute', 0, false, null, 0], //13 + + ['dropdown_attribute', 0, '-', 1, 1], //14 + ['dropdown_attribute', 0, '-', '', null], //15 + ['dropdown_attribute', 0, '-', null, 0], //16 + ['dropdown_attribute', 0, '-', false, 0], //17 + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/Validator/Attribute/BackendTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/Validator/Attribute/BackendTest.php index f9c49dfeaa78b..2afd02312778f 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/Validator/Attribute/BackendTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/Validator/Attribute/BackendTest.php @@ -1,6 +1,6 @@ getArea(Area::AREA_FRONTEND) ->load(); - $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; + $expectedViewUrl = '/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; $this->model->setDesignConfig([ 'area' => 'frontend', 'store' => $this->objectManager->get(\Magento\Store\Model\StoreManagerInterface::class) @@ -578,7 +578,6 @@ public function testGetProcessedTemplateSubject() ->getArea(Area::AREA_FRONTEND) ->load(); - $expectedViewUrl = 'static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico'; $this->model->setTemplateSubject('{{view url="Magento_Theme::favicon.ico"}}'); $this->model->setDesignConfig([ 'area' => 'frontend', @@ -588,10 +587,16 @@ public function testGetProcessedTemplateSubject() ]); $this->setNotDefaultThemeForFixtureStore(); - $this->assertStringEndsNotWith($expectedViewUrl, $this->model->getProcessedTemplateSubject([])); + $this->assertStringMatchesFormat( + '%s/frontend/Magento/luma/en_US/Magento_Theme/favicon.ico', + $this->model->getProcessedTemplateSubject([]) + ); $this->setDefaultThemeForFixtureStore(); - $this->assertStringEndsWith($expectedViewUrl, $this->model->getProcessedTemplateSubject([])); + $this->assertStringMatchesFormat( + '%s/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico', + $this->model->getProcessedTemplateSubject([]) + ); } /** @@ -605,7 +610,7 @@ public function testGetDefaultEmailLogo() ->load(); $this->assertStringEndsWith( - 'static/frontend/Magento/luma/en_US/Magento_Email/logo_email.png', + '/frontend/Magento/luma/en_US/Magento_Email/logo_email.png', $this->model->getDefaultEmailLogo() ); } diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/footer.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/footer.html index 32c85082ed403..f991f7d527d4d 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/footer.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/footer.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/header.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/header.html index c3b9bae777f07..e801adc64b32c 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/header.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/code/Magento/Email/view/email/header.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/layout/email_template_test_handle.xml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/layout/email_template_test_handle.xml index bd413a2b358c2..27c2bab576c9d 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/layout/email_template_test_handle.xml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/layout/email_template_test_handle.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml index 46c67a5e11090..569be98f53948 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html index be8e2261ee049..f2c24e49f4d42 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/registration.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/registration.php index 531616fa8eeb2..fd4c612b16a6b 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/custom_theme/registration.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/custom_theme/registration.php index 6205084427195..795c3fd9ed1f5 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/custom_theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/custom_theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/default/registration.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/default/registration.php index ff55b30ee27b6..154559b536c69 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Vendor/default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html index 9f30dbc919951..31075037a6736 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/layout/email_template_test_handle.xml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/layout/email_template_test_handle.xml index 0ca53310587ce..0b11473708b7c 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/layout/email_template_test_handle.xml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/layout/email_template_test_handle.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml index 029904c742106..0d243b969d340 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml index b845bb5076b4d..492f006936b55 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/registration.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/registration.php index a7be0ebbd8a4c..7cca51d524ec1 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-3.less b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-3.less index bd6e70a4966d1..0451172608316 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-3.less +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-3.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ p { diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-inline-3.less b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-inline-3.less index 9107efbcf54ae..9863f81a6f503 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-inline-3.less +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/email-inline-3.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ p { diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/file-with-error.less b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/file-with-error.less index a6c1c567b4046..e8c1d877a437b 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/file-with-error.less +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/web/css/file-with-error.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ p { diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html index 82b2ffb637eb8..eedb590d2dfc0 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/registration.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/registration.php index 5a81b84232ff5..258baa43ba026 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-1.less b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-1.less index 659fe30a3e783..8ca70ea16c33c 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-1.less +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-1.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ p { diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-inline-1.less b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-inline-1.less index 3c03e94fb5cc3..11b739019889e 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-inline-1.less +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/web/css/email-inline-1.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ p { diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html index 35c53d9a8d138..46cd9c696883f 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/registration.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/registration.php index c5258bb49ba18..0ea6b6e962568 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-2.less b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-2.less index 8c2853c0f03c6..9115edf7aa593 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-2.less +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-2.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ p { diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-inline-2.less b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-inline-2.less index 4094444a8b1b7..aae6da394e0e0 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-inline-2.less +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/web/css/email-inline-2.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ p { diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php index efbd2957a8b2a..b5ed5bc448e38 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php @@ -1,6 +1,6 @@ assertNotContains($testValue, $values1); + $this->assertRegExp('/([0-9]+:)([0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+)/', current($values1)); // Verify that the credit card number has been encrypted $values2 = $connection->fetchPairs( @@ -88,6 +89,7 @@ public function testChangeEncryptionKey() ) ); $this->assertNotContains('1111111111', $values2); + $this->assertRegExp('/([0-9]+:)([0-9]+:)([a-zA-Z0-9]+:)([a-zA-Z0-9]+)/', current($values1)); /** clean up */ $select = $connection->select()->from($configModel->getMainTable())->where('path=?', $testPath); diff --git a/dev/tests/integration/testsuite/Magento/EncryptionKey/_files/payment_info.php b/dev/tests/integration/testsuite/Magento/EncryptionKey/_files/payment_info.php index 35be92b82998c..68db088d82428 100644 --- a/dev/tests/integration/testsuite/Magento/EncryptionKey/_files/payment_info.php +++ b/dev/tests/integration/testsuite/Magento/EncryptionKey/_files/payment_info.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/Config/_files/config_two.xml b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/Config/_files/config_two.xml index 1fddb41deb254..aafc740bb7b90 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/Config/_files/config_two.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/Config/_files/config_two.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/JoinProcessorTest.php b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/JoinProcessorTest.php index e289f02608668..b50db64aacd9b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/JoinProcessorTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/ExtensionAttribute/JoinProcessorTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Api/etc/extension_attributes.xml b/dev/tests/integration/testsuite/Magento/Framework/Api/etc/extension_attributes.xml index 49964f70175c5..a5a2f9ed5f1e9 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Api/etc/extension_attributes.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Api/etc/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/AreaTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/AreaTest.php index 9f374b1ca16e8..8d5241a6d93aa 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/AreaTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/AreaTest.php @@ -1,6 +1,6 @@ get(\Magento\Framework\App\CacheInterface::class) ->clean([\Magento\Framework\App\Config::CACHE_TAG]); \Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize(); + $appConfig = ObjectManager::getInstance()->get(Config::class); + $appConfig->clean(); } protected function setUp() diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Config/InitialTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/Config/InitialTest.php new file mode 100644 index 0000000000000..bf33ba97da23b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Config/InitialTest.php @@ -0,0 +1,55 @@ +objectManager = Bootstrap::getObjectManager(); + } + + public function testGetMetadata() + { + CacheCleaner::cleanAll(); + $this->assertEquals( + $this->objectManager->create(Config::class)->getMetadata(), + $this->objectManager->create(Config::class)->getMetadata() + ); + } + + /** + * @param string $scope + * @dataProvider getDataDataProvider + */ + public function testGetData($scope) + { + CacheCleaner::cleanAll(); + $this->assertEquals( + $this->objectManager->create(Config::class)->getData($scope), + $this->objectManager->create(Config::class)->getData($scope) + ); + } + + public function getDataDataProvider() + { + return [ + ['default'], + ['stores|default'], + ['websites|default'] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/FrontControllerTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/FrontControllerTest.php index ae5df85e9cb8b..649cef5d7509b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/FrontControllerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/FrontControllerTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_gb/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_gb/registration.php index 0954744f7fbf5..a47a4923fd08f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_gb/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_gb/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_us/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_us/registration.php index 65dd0fc09513e..71b3ed2f4ebd4 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_us/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/bar/en_us/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/baz/en_gb/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/baz/en_gb/registration.php index 8b2410a43a889..ce98869142cd9 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/baz/en_gb/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/baz/en_gb/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/first/en_us/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/first/en_us/registration.php index 9da15f77433b3..c1463b2dfbe41 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/first/en_us/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/first/en_us/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/foo/en_au/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/foo/en_au/registration.php index 919ffc1da1bb8..b0974574d53a4 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/foo/en_au/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/foo/en_au/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/my/ru_ru/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/my/ru_ru/registration.php index e4852d389e152..596c8ad6053d7 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/my/ru_ru/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/my/ru_ru/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/second/en_gb/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/second/en_gb/registration.php index f68272182e557..9d05acc2f480b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/second/en_gb/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/second/en_gb/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/theirs/ru_ru/registration.php b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/theirs/ru_ru/registration.php index f579ee24ad781..681857d4f3ee8 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/theirs/ru_ru/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Language/_files/theirs/ru_ru/registration.php @@ -1,6 +1,6 @@ object = $objectManager->create( + \Magento\Framework\App\ObjectManager\ConfigLoader::class + ); + } + + public function testLoad() + { + CacheCleaner::cleanAll(); + $data = $this->object->load('global'); + $this->assertNotEmpty($data); + $cachedData = $this->object->load('global'); + $this->assertEquals($data, $cachedData); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/ResourceConnection/ConnectionFactoryTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/ResourceConnection/ConnectionFactoryTest.php index 977e29a93415f..3faedaa75626c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/ResourceConnection/ConnectionFactoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/ResourceConnection/ConnectionFactoryTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + } + + /** + * @param string $route + * @param string $scope + * @dataProvider getRouteFrontNameDataProvider + */ + public function testGetRouteFrontName($route, $scope) + { + CacheCleaner::cleanAll(); + $this->assertEquals( + $this->objectManager->create(Config::class)->getRouteFrontName($route, $scope), + $this->objectManager->create(Config::class)->getRouteFrontName($route, $scope) + ); + } + + public function getRouteFrontNameDataProvider() + { + return [ + ['adminhtml', 'adminhtml'], + ['catalog', 'frontend'], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Router/BaseTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/Router/BaseTest.php index ac04e1198034f..36c23466f8631 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Router/BaseTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Router/BaseTest.php @@ -1,6 +1,6 @@ fileStorage = ObjectManager::getInstance()->create( + File::class, + [ + 'directoryCode' => DirectoryList::STATIC_VIEW, + 'fileName' => $this->fileName + ] + ); + /** @var \Magento\TestFramework\App\Filesystem $filesystem */ + $filesystem = ObjectManager::getInstance()->get(\Magento\TestFramework\App\Filesystem::class); + $this->directoryWrite = $filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); + $this->removeDeployVersionFile(); + } + + /** + * @param string $mode + * @return Version + */ + public function getVersionModel($mode) + { + $appState = ObjectManager::getInstance()->create( + State::class, + [ + 'mode' => $mode + ] + ); + return ObjectManager::getInstance()->create( + Version::class, + [ + 'appState' => $appState + ] + ); + } + + protected function tearDown() + { + $this->removeDeployVersionFile(); + } + + private function removeDeployVersionFile() + { + if ($this->directoryWrite->isExist($this->fileName)) { + $this->directoryWrite->delete($this->fileName); + } + } + + /** + * @expectedException \UnexpectedValueException + */ + public function testGetValueInProductionModeWithoutVersion() + { + $this->assertFalse($this->directoryWrite->isExist($this->fileName)); + $this->getVersionModel(State::MODE_PRODUCTION)->getValue(); + } + + public function testGetValueInDeveloperMode() + { + $this->assertFalse($this->directoryWrite->isExist($this->fileName)); + $this->getVersionModel(State::MODE_DEVELOPER)->getValue(); + $this->assertTrue($this->directoryWrite->isExist($this->fileName)); + } + + /** + * Assert that version is not regenerated on each request in developer mode + */ + public function testGetValue() + { + $this->assertFalse($this->directoryWrite->isExist($this->fileName)); + $versionModel = $this->getVersionModel(State::MODE_DEVELOPER); + $version = $versionModel->getValue(); + $this->assertTrue($this->directoryWrite->isExist($this->fileName)); + $this->assertEquals($version, $versionModel->getValue()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Backup/FilesystemTest.php b/dev/tests/integration/testsuite/Magento/Framework/Backup/FilesystemTest.php new file mode 100644 index 0000000000000..56e75b5bc0e83 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Backup/FilesystemTest.php @@ -0,0 +1,50 @@ +objectManager = Bootstrap::getObjectManager(); + $this->filesystem = $this->objectManager->create(\Magento\Framework\Backup\Filesystem::class); + } + + /** + * @magentoAppIsolation enabled + */ + public function testRollback() + { + $rootDir = Bootstrap::getInstance()->getAppTempDir() + . '/rollback_test_' . time(); + $backupsDir = __DIR__ . '/_files/var/backups'; + $fileName = 'test.txt'; + + mkdir($rootDir); + + $this->filesystem->setRootDir($rootDir) + ->setBackupsDir($backupsDir) + ->setTime(1474538269) + ->setName('code') + ->setBackupExtension('tgz'); + + $this->assertTrue($this->filesystem->rollback()); + $this->assertTrue(file_exists($rootDir . '/' . $fileName)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Backup/_files/var/backups/1474538269_filesystem_code.tgz b/dev/tests/integration/testsuite/Magento/Framework/Backup/_files/var/backups/1474538269_filesystem_code.tgz new file mode 100644 index 0000000000000..6e972c35672a8 Binary files /dev/null and b/dev/tests/integration/testsuite/Magento/Framework/Backup/_files/var/backups/1474538269_filesystem_code.tgz differ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Cache/Backend/MongoDbTest.php b/dev/tests/integration/testsuite/Magento/Framework/Cache/Backend/MongoDbTest.php index 1e152af525d02..41126ea361b8d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Cache/Backend/MongoDbTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Cache/Backend/MongoDbTest.php @@ -1,6 +1,6 @@ assertEquals($expectedParsedTopics, $topics); } + /** + * Get topic configuration by its name + * + * @expectedException \LogicException + * @expectedExceptionMessage Service method specified in the definition of topic "customerDeletedNumbers" is not av + */ + public function testGetTopicsNumeric() + { + $this->getConfigInstance(__DIR__ . '/_files/valid_communication_numeric.xml')->getTopics(); + } + + // @codingStandardsIgnoreStart + /** + * Get topic configuration by its name + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Invalid XML in file 0: + Element 'topic', attribute 'schema': [facet 'pattern'] The value '55\Customer\Api\CustomerRepositoryInterface::delete' is not accepted by the pattern '[a-zA-Z]+[a-zA-Z0-9\\]+::[a-zA-Z0-9]+'. + Line: 9 + + Element 'topic', attribute 'schema': '55\Customer\Api\CustomerRepositoryInterface::delete' is not a valid value of the atomic type 'schemaType'. + Line: 9 + + Element 'handler', attribute 'type': [facet 'pattern'] The value '55\Customer\Api\CustomerRepositoryInterface' is not accepted by the pattern '[a-zA-Z]+[a-zA-Z0-9\\]+'. + Line: 10 + + Element 'handler', attribute 'type': '55\Customer\Api\CustomerRepositoryInterface' is not a valid value of the atomic type 'serviceTypeType'. + Line: 10 + * + */ + // @codingStandardsIgnoreEnd + public function testGetTopicsNumericInvalid() + { + $this->getConfigInstance(__DIR__ . '/_files/invalid_communication_numeric.xml')->getTopics(); + } + /** * Get topic configuration by its name */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_incorrect_request_schema_type.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_incorrect_request_schema_type.php index 3bad237d731b3..dc9736fc309e9 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_incorrect_request_schema_type.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_incorrect_request_schema_type.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_missing_request.xml b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_missing_request.xml index 703c681b90df8..ebfad2afbe8c2 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_missing_request.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_missing_request.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_multiple_handlers_synchronous_mode.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_multiple_handlers_synchronous_mode.php index ff2c6f946efc7..7297440d5a8c6 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_multiple_handlers_synchronous_mode.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_multiple_handlers_synchronous_mode.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_no_attributes.xml b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_no_attributes.xml index fa37c34c11009..20c846cf7899f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_no_attributes.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_no_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_handler_method.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_handler_method.php index 72c95e2578da1..f483fc87d407f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_handler_method.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_handler_method.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service.xml b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service.xml index b604e71acdec8..a915ac1228b26 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service_method.xml b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service_method.xml index 7269469ef302b..61034f55ad00d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service_method.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_not_existing_service_method.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_request_not_existing_service.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_request_not_existing_service.php index d561435144388..ee7a8690c0ae8 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_request_not_existing_service.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_request_not_existing_service.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_response_not_existing_service.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_response_not_existing_service.php index d0435662c5aa1..03ac5e96eb659 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_response_not_existing_service.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_response_not_existing_service.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_topic_with_excessive_keys.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_topic_with_excessive_keys.php index 3ce07b1654955..5fea642091c3f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_topic_with_excessive_keys.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/communication_topic_with_excessive_keys.php @@ -1,6 +1,6 @@ + + + + + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication.xml b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication.xml index f3c8cf3ccdbb4..7ea9ea1a215aa 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication_expected.php b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication_expected.php index 2ab666428c9ff..9181c2a704808 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication_expected.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Communication/_files/valid_communication_expected.php @@ -1,6 +1,6 @@ + + + + + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php b/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php index 87c716631a558..b9d2c876c2164 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/ComposerInformationTest.php @@ -1,6 +1,6 @@ getMock( - \Magento\Framework\Composer\MagentoComposerApplicationFactory::class, - [], - [], - '', - false - ); + $composerAppFactory = $this->getMockBuilder(MagentoComposerApplicationFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $composerApp = $this->getMockBuilder(MagentoComposerApplication::class) + ->disableOriginalConstructor() + ->getMock(); - $composerApp = $this->getMock( - \Magento\Composer\MagentoComposerApplication::class, - [], - [], - '', - false - ); - - $composerApp->expects($this->once())->method('runComposerCommand'); - - $composerAppFactory->expects($this->once())->method('create')->willReturn($composerApp); + $composerApp->expects($this->once()) + ->method('runComposerCommand') + ->with( + [ + 'command' => 'remove', + 'packages' => ['magento/package-a', 'magento/package-b'], + '--no-update' => true, + ] + ); + $composerAppFactory->expects($this->once()) + ->method('create') + ->willReturn($composerApp); $remove = new Remove($composerAppFactory); $remove->remove(['magento/package-a', 'magento/package-b']); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/vendor/README b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/vendor/README index 2539c0099e93c..2685c30891c00 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/vendor/README +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/vendor/README @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ This file is to create a vendor directory for testing diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/vendor/README b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/vendor/README index 2539c0099e93c..2685c30891c00 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/vendor/README +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/vendor/README @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ This file is to create a vendor directory for testing diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/vendor/README b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/vendor/README index 2539c0099e93c..2685c30891c00 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/vendor/README +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/vendor/README @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ This file is to create a vendor directory for testing diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/vendor_path.php b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/vendor_path.php index 25fc1e1b2c668..1734081dfe051 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/vendor_path.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/vendor_path.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/design/frontend/Test/parent/registration.php b/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/design/frontend/Test/parent/registration.php index 52a4a16d18578..d28ccf420b321 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/design/frontend/Test/parent/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/design/frontend/Test/parent/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/lib/web/3.less b/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/lib/web/3.less index de8d6883243ac..8a468d5f9aeac 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/lib/web/3.less +++ b/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/_files/lib/web/3.less @@ -1,6 +1,6 @@ /** * @category design - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/InterfaceTest.php b/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/InterfaceTest.php index 400343ced0752..d2b912384d2d1 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/InterfaceTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/InterfaceTest.php @@ -1,6 +1,6 @@ _connection)) { - /** @var $coreResource \Magento\Framework\App\ResourceConnection */ + /** @var $coreResource ResourceConnection */ $coreResource = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->get(\Magento\Framework\App\ResourceConnection::class); + ->get(ResourceConnection::class); $this->_connection = $coreResource->getConnection(); } return $this->_connection; diff --git a/dev/tests/integration/testsuite/Magento/Framework/DB/HelperTest.php b/dev/tests/integration/testsuite/Magento/Framework/DB/HelperTest.php index c137278d23db6..75120accc348e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DB/HelperTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/DB/HelperTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetFirst.xml b/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetFirst.xml index e4e0ef8aa536c..62f1ee9efc2e3 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetFirst.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetFirst.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetSecond.xml b/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetSecond.xml index 5e8cb97c738d0..3a0a7f59db705 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetSecond.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/DataObject/Copy/Config/_files/partialFieldsetSecond.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php b/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php index 0a2662ce46c85..692c7d64c68a4 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/DataObject/CopyTest.php @@ -1,6 +1,6 @@ markTestSkipped('Workaround for problem with imagettfbbox() function on Travis'); + } $adapter = $this->_getAdapter($adapterType); /** @var \Magento\Framework\Filesystem\Directory\ReadFactory readFactory */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php index 5c0406ec372a5..e91e125a5d64f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/AbstractPlugin.php @@ -1,6 +1,6 @@ $cache, \Magento\Framework\Config\ScopeInterface::class => $configScope, @@ -79,7 +80,8 @@ public function setUpInterceptionConfig($pluginConfig) \Magento\Framework\ObjectManager\ConfigInterface::class => $config, \Magento\Framework\Interception\ObjectManager\ConfigInterface::class => $config, \Magento\Framework\ObjectManager\DefinitionInterface::class => $definitions, - \Magento\Framework\Interception\DefinitionInterface::class => $interceptionDefinitions + \Magento\Framework\Interception\DefinitionInterface::class => $interceptionDefinitions, + \Magento\Framework\Serialize\SerializerInterface::class => $json, ]; $this->_objectManager = new \Magento\Framework\ObjectManager\ObjectManager( $factory, diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/Fixture/Intercepted.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/Fixture/Intercepted.php index 24aac955c3012..3e3ec23c0b30d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/Fixture/Intercepted.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/Fixture/Intercepted.php @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_one.xml b/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_one.xml index ddc02072874ea..099a29035fcb7 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_one.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_one.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_two.xml b/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_two.xml index a8e8f4f9bfda0..2cc41879dda68 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_two.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/ObjectManager/_files/config_two.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Pricing/Helper/DataTest.php b/dev/tests/integration/testsuite/Magento/Framework/Pricing/Helper/DataTest.php index 403f84a7e6209..fff66ba75072d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Pricing/Helper/DataTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Pricing/Helper/DataTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Profiler/Driver/Standard/Output/_files/timers.php b/dev/tests/integration/testsuite/Magento/Framework/Profiler/Driver/Standard/Output/_files/timers.php index 2e5c8d6dd75ca..7169acdb9515b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Profiler/Driver/Standard/Output/_files/timers.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Profiler/Driver/Standard/Output/_files/timers.php @@ -2,7 +2,7 @@ /** * Fixture timers statistics for output tests * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ $timer = new \Magento\Framework\Profiler\Driver\Standard\Stat(); diff --git a/dev/tests/integration/testsuite/Magento/Framework/ProfilerTest.php b/dev/tests/integration/testsuite/Magento/Framework/ProfilerTest.php index ab32598d340d3..2ad6f42007875 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/ProfilerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/ProfilerTest.php @@ -2,7 +2,7 @@ /** * Test case for \Magento\Framework\Profiler * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework; diff --git a/dev/tests/integration/testsuite/Magento/Framework/Reflection/MethodsMapTest.php b/dev/tests/integration/testsuite/Magento/Framework/Reflection/MethodsMapTest.php new file mode 100644 index 0000000000000..9433ccff57763 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Reflection/MethodsMapTest.php @@ -0,0 +1,48 @@ +object = $objectManager->create( + \Magento\Framework\Reflection\MethodsMap::class + ); + } + + public function testGetMethodsMap() + { + CacheCleaner::cleanAll(); + $data = $this->object->getMethodsMap(\Magento\Framework\Reflection\MethodsMap::class); + $this->assertArrayHasKey('getMethodsMap', $data); + $cachedData = $this->object->getMethodsMap(\Magento\Framework\Reflection\MethodsMap::class); + $this->assertEquals($data, $cachedData); + } + + public function testGetMethodParams() + { + CacheCleaner::cleanAll(); + $data = $this->object->getMethodParams( + \Magento\Framework\Reflection\MethodsMap::class, + 'getMethodParams' + ); + $this->assertCount(2, $data); + $cachedData = $this->object->getMethodParams( + \Magento\Framework\Reflection\MethodsMap::class, + 'getMethodParams' + ); + $this->assertEquals($data, $cachedData); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php index 9acfa6f1caab1..0c298d5a89787 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/AdapterTest.php @@ -1,6 +1,6 @@ assertEquals($expectedRecordsCount, $queryResponse->count()); } + /** + * @magentoDataFixture Magento/Framework/Search/_files/product_configurable.php + * @magentoConfigFixture current_store catalog/search/engine mysql + */ + public function testAdvancedSearchCompositeProductWithOutOfStockOption() + { + /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */ + $attribute = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'test_configurable'); + /** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection $selectOptions */ + $selectOptions = $this->objectManager + ->create(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class) + ->setAttributeFilter($attribute->getId()); + + $firstOption = $selectOptions->getFirstItem(); + $firstOptionId = $firstOption->getId(); + $this->requestBuilder->bind('test_configurable', $firstOptionId); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(0, $queryResponse->count()); + + $secondOption = $selectOptions->getLastItem(); + $secondOptionId = $secondOption->getId(); + $this->requestBuilder->bind('test_configurable', $secondOptionId); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(1, $queryResponse->count()); + } + + /** + * @magentoDataFixture Magento/Framework/Search/_files/product_configurable_with_disabled_child.php + * @magentoConfigFixture current_store catalog/search/engine mysql + */ + public function testAdvancedSearchCompositeProductWithDisabledChild() + { + /** @var \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute */ + $attribute = $this->objectManager->get(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class) + ->loadByCode(\Magento\Catalog\Model\Product::ENTITY, 'test_configurable'); + /** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection $selectOptions */ + $selectOptions = $this->objectManager + ->create(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class) + ->setAttributeFilter($attribute->getId()); + + $firstOption = $selectOptions->getFirstItem(); + $firstOptionId = $firstOption->getId(); + $this->requestBuilder->bind('test_configurable', $firstOptionId); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(0, $queryResponse->count()); + + $secondOption = $selectOptions->getLastItem(); + $secondOptionId = $secondOption->getId(); + $this->requestBuilder->bind('test_configurable', $secondOptionId); + $this->requestBuilder->setRequestName('filter_out_of_stock_child'); + + $queryResponse = $this->executeQuery(); + $this->assertEquals(0, $queryResponse->count()); + } + public function dateDataProvider() { return [ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/Builder/Query/MatchTest.php b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/Builder/Query/MatchTest.php index 3f11fe1584a18..c638458e87742 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/Builder/Query/MatchTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/Adapter/Mysql/Builder/Query/MatchTest.php @@ -1,6 +1,6 @@ get(\Magento\Eav\Model\Config::class); +$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable'); + +$eavConfig->clear(); + +/** @var $installer \Magento\Catalog\Setup\CategorySetup */ +$installer = Bootstrap::getObjectManager()->create(\Magento\Catalog\Setup\CategorySetup::class); + +if (!$attribute->getId()) { + + /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ + $attribute = Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class + ); + + /** @var AttributeRepositoryInterface $attributeRepository */ + $attributeRepository = Bootstrap::getObjectManager()->create(AttributeRepositoryInterface::class); + + $attribute->setData( + [ + 'attribute_code' => 'test_configurable', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'select', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_comparable' => 0, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Test Configurable'], + 'backend_type' => 'int', + 'option' => [ + 'value' => ['option_0' => ['Option 1'], 'option_1' => ['Option 2']], + 'order' => ['option_0' => 1, 'option_1' => 2], + ], + ] + ); + + $attributeRepository->save($attribute); +} + +/* Assign attribute to attribute set */ +$installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); +$eavConfig->clear(); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute_rollback.php new file mode 100644 index 0000000000000..2ed4c07efbe39 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/configurable_attribute_rollback.php @@ -0,0 +1,28 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +$productCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Model\ResourceModel\Product\Collection::class); +foreach ($productCollection as $product) { + $product->delete(); +} + +$eavConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class); +$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable'); +if ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AbstractAttribute + && $attribute->getId() +) { + $attribute->delete(); +} +$eavConfig->clear(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php index 97276c02574c9..db26b94e93881 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/date_attribute.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/etc/search_request_2.xml b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/etc/search_request_2.xml index 2f175f3b9ceaa..9fa37f12b28b2 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/etc/search_request_2.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/etc/search_request_2.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php index 0fbf2b1376d34..5956440e3de79 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/filterable_attribute.php @@ -1,6 +1,6 @@ create( diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable.php new file mode 100644 index 0000000000000..c38b437f888c3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable.php @@ -0,0 +1,121 @@ +reinitialize(); + +require __DIR__ . '/configurable_attribute.php'; + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = Bootstrap::getObjectManager() + ->create(ProductRepositoryInterface::class); + +/** @var $installer CategorySetup */ +$installer = Bootstrap::getObjectManager()->create(CategorySetup::class); + +/* Create simple products per each option value*/ +/** @var AttributeOptionInterface[] $options */ +$options = $attribute->getOptions(); + +$attributeValues = []; +$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default'); +$associatedProductIds = []; +$productIds = [1010, 1020]; +array_shift($options); //remove the first option which is empty + +$isFirstOption = true; +foreach ($options as $option) { + /** @var $product Product */ + $product = Bootstrap::getObjectManager()->create(Product::class); + $productId = array_shift($productIds); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setId($productId) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Option' . $option->getLabel()) + ->setSku('simple_' . $productId) + ->setPrice($productId) + ->setTestConfigurable($option->getValue()) + ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => (int)!$isFirstOption, + ] + ); + + $product = $productRepository->save($product); + + /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */ + $stockItem = Bootstrap::getObjectManager()->create(\Magento\CatalogInventory\Model\Stock\Item::class); + $stockItem->load($productId, 'product_id'); + + if (!$stockItem->getProductId()) { + $stockItem->setProductId($productId); + } + $stockItem->setUseConfigManageStock(1); + $stockItem->setQty(1000); + $stockItem->setIsQtyDecimal(0); + $stockItem->setIsInStock((int)!$isFirstOption); + $stockItem->save(); + + $attributeValues[] = [ + 'label' => 'test', + 'attribute_id' => $attribute->getId(), + 'value_index' => $option->getValue(), + ]; + $associatedProductIds[] = $product->getId(); + $isFirstOption = false; +} + +/** @var $product Product */ +$product = Bootstrap::getObjectManager()->create(Product::class); + +/** @var Factory $optionsFactory */ +$optionsFactory = Bootstrap::getObjectManager()->create(Factory::class); + +$configurableAttributesData = [ + [ + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'label' => $attribute->getStoreLabel(), + 'position' => '0', + 'values' => $attributeValues, + ], +]; + +$configurableOptions = $optionsFactory->create($configurableAttributesData); + +$extensionConfigurableAttributes = $product->getExtensionAttributes(); +$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions); +$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds); + +$product->setExtensionAttributes($extensionConfigurableAttributes); + +$product->setTypeId(Configurable::TYPE_CODE) + ->setId(1001) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Product') + ->setSku('configurable') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_rollback.php new file mode 100644 index 0000000000000..6411013ca6e9e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_rollback.php @@ -0,0 +1,36 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +foreach (['simple_1010', 'simple_1020', 'configurable'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + + $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class); + $stockStatus->load($product->getEntityId(), 'product_id'); + $stockStatus->delete(); + + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed + } +} + +require __DIR__ . '/configurable_attribute_rollback.php'; + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_with_disabled_child.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_with_disabled_child.php new file mode 100644 index 0000000000000..d58df460ddab8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_with_disabled_child.php @@ -0,0 +1,18 @@ +create(ProductRepositoryInterface::class); + +$product = $productRepository->get('simple_1020'); +$product->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_DISABLED); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_with_disabled_child_rollback.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_with_disabled_child_rollback.php new file mode 100644 index 0000000000000..a1fe103a2d4ca --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/product_configurable_with_disabled_child_rollback.php @@ -0,0 +1,7 @@ + @@ -387,4 +387,24 @@ 0 10 + + + + + + + + + + + + + + + + + 0 + 10 + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request.xml b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request.xml index 1c304aaf6ffd3..c676cd138cfe6 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request.xml @@ -1,7 +1,7 @@ @@ -59,4 +59,4 @@ 10 10 - \ No newline at end of file + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request_config.php b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request_config.php index b5d2f7c46fd75..cb985792aa2fe 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request_config.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Search/_files/search_request_config.php @@ -1,6 +1,6 @@ markTestSkipped('MAGETWO-56529'); - // Set expected session.save_handler config - if ($deploymentConfigHandler) { - if ($deploymentConfigHandler !== 'files') { - $expected = 'user'; - } else { - $expected = $deploymentConfigHandler; - } - } else if ($iniHandler) { - $expected = $iniHandler; - } else { - $expected = SaveHandlerInterface::DEFAULT_HANDLER; - } + $expected = $this->getExpectedSaveHandler($deploymentConfigHandler, $iniHandler); // Set ini configuration if ($iniHandler) { ini_set('session.save_handler', $iniHandler); } - + $defaultHandler = ini_get('session.save_handler') ?: SaveHandlerInterface::DEFAULT_HANDLER; /** @var DeploymentConfig | \PHPUnit_Framework_MockObject_MockObject $deploymentConfigMock */ $deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class) ->disableOriginalConstructor() ->getMock(); $deploymentConfigMock->expects($this->once()) ->method('get') - ->with(Config::PARAM_SESSION_SAVE_METHOD, SaveHandlerInterface::DEFAULT_HANDLER) + ->with(Config::PARAM_SESSION_SAVE_METHOD, $defaultHandler) ->willReturn($deploymentConfigHandler ?: SaveHandlerInterface::DEFAULT_HANDLER); new SaveHandler( @@ -85,4 +73,31 @@ public function saveHandlerProvider() [false, false], ]; } + + /** + * Retrieve expected session.save_handler + * + * @param string $deploymentConfigHandler + * @param string $iniHandler + * @return string + */ + private function getExpectedSaveHandler($deploymentConfigHandler, $iniHandler) + { + // Set expected session.save_handler config + if ($deploymentConfigHandler) { + if ($deploymentConfigHandler !== 'files') { + $expected = 'user'; + return $expected; + } else { + $expected = $deploymentConfigHandler; + return $expected; + } + } elseif ($iniHandler) { + $expected = $iniHandler; + return $expected; + } else { + $expected = SaveHandlerInterface::DEFAULT_HANDLER; + return $expected; + } + } } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php index ed1eddf96cc6b..11a436d1935d6 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_inline_page_original.html b/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_inline_page_original.html index 554f9b2a463f3..2b7dc56da5642 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_inline_page_original.html +++ b/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_inline_page_original.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_translation_data.php b/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_translation_data.php index f082a1fee8495..1e464ad050647 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_translation_data.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Translate/_files/_translation_data.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/TranslateCachingTest.php b/dev/tests/integration/testsuite/Magento/Framework/TranslateCachingTest.php index fbbc2ffc7bd1b..ec95a4511cd95 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/TranslateCachingTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/TranslateCachingTest.php @@ -1,13 +1,17 @@ expects($this->any())->method('getDesignTheme')->will($this->returnValue($theme)); + /** @var \Magento\TestFramework\ObjectManager $objectManager */ $objectManager = Bootstrap::getObjectManager(); $objectManager->addSharedInstance($viewFileSystem, \Magento\Framework\View\FileSystem::class); @@ -71,19 +77,31 @@ protected function setUp() $objectManager->addSharedInstance($designModel, \Magento\Theme\Model\View\Design\Proxy::class); - $model = $objectManager->create(\Magento\Framework\Translate::class); - $objectManager->addSharedInstance($model, \Magento\Framework\Translate::class); + $this->translate = $objectManager->create(\Magento\Framework\Translate::class); + $objectManager->addSharedInstance($this->translate, \Magento\Framework\Translate::class); $objectManager->removeSharedInstance(\Magento\Framework\Phrase\Renderer\Composite::class); $objectManager->removeSharedInstance(\Magento\Framework\Phrase\Renderer\Translate::class); - \Magento\Framework\Phrase::setRenderer($objectManager->get(\Magento\Framework\Phrase\RendererInterface::class)); - $model->loadData(\Magento\Framework\App\Area::AREA_FRONTEND); + \Magento\Framework\Phrase::setRenderer( + $objectManager->get(\Magento\Framework\Phrase\RendererInterface::class) + ); + } + + public function testLoadData() + { + $data = $this->translate->loadData(null, true)->getData(); + CacheCleaner::cleanAll(); + $this->translate->loadData()->getData(); + $dataCached = $this->translate->loadData()->getData(); + $this->assertEquals($data, $dataCached); } /** + * @magentoCache all disabled * @dataProvider translateDataProvider */ public function testTranslate($inputText, $expectedTranslation) { + $this->translate->loadData(\Magento\Framework\App\Area::AREA_FRONTEND); $actualTranslation = new \Magento\Framework\Phrase($inputText); $this->assertEquals($expectedTranslation, $actualTranslation); } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Url/Helper/DataTest.php b/dev/tests/integration/testsuite/Magento/Framework/Url/Helper/DataTest.php index 2a908155a95af..69fe4ffe7c3fb 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Url/Helper/DataTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Url/Helper/DataTest.php @@ -1,6 +1,6 @@ _testCssMinification( - '/frontend/FrameworkViewMinifier/default/en_US/css/styles.min.css', + '/frontend/FrameworkViewMinifier/default/en_US/css/styles.css', function ($path) { - $this->assertEquals( + $content = file_get_contents($path); + $this->assertNotEmpty($content); + $this->assertContains('FrameworkViewMinifier/frontend', $content); + $this->assertNotEquals( file_get_contents( dirname(__DIR__) . '/_files/static/expected/styles.magento.min.css' ), - file_get_contents($path), - 'Minified files are not equal or minification did not work for requested CSS' + $content, + 'CSS is minified when minification turned off' ); } ); } /** - * @magentoConfigFixture current_store dev/css/minify_files 0 + * @magentoConfigFixture current_store dev/css/minify_files 1 */ - public function testCssMinificationOff() + public function testCssMinification() { $this->_testCssMinification( - '/frontend/FrameworkViewMinifier/default/en_US/css/styles.css', + '/frontend/FrameworkViewMinifier/default/en_US/css/styles.min.css', function ($path) { - $content = file_get_contents($path); - $this->assertNotEmpty($content); - $this->assertContains('FrameworkViewMinifier/frontend', $content); - $this->assertNotEquals( + $this->assertEquals( file_get_contents( dirname(__DIR__) . '/_files/static/expected/styles.magento.min.css' ), - $content, - 'CSS is minified when minification turned off' + file_get_contents($path), + 'Minified files are not equal or minification did not work for requested CSS' ); } ); @@ -234,13 +235,13 @@ public function testDeploymentWithMinifierEnabled() ] )); - /** @var \Magento\Deploy\Model\Deployer $deployer */ + /** @var \Magento\Deploy\Model\Deploy\LocaleDeploy $deployer */ $deployer = $this->objectManager->create( - \Magento\Deploy\Model\Deployer::class, + \Magento\Deploy\Model\Deploy\LocaleDeploy::class, ['filesUtil' => $filesUtil, 'output' => $output] ); - $deployer->deploy($omFactory, ['en_US'], ['frontend' => ['FrameworkViewMinifier/default']]); + $deployer->deploy('frontend', 'FrameworkViewMinifier/default', 'en_US', []); $this->assertFileExists($fileToBePublished); $this->assertEquals( diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Design/Fallback/RulePoolTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Design/Fallback/RulePoolTest.php index 37a4f3facca78..3a8dd59feffd9 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Design/Fallback/RulePoolTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Design/Fallback/RulePoolTest.php @@ -1,6 +1,6 @@ _block->getViewFileUrl('css/styles.css'); - $this->assertStringMatchesFormat('http://localhost/pub/static/frontend/%s/en_US/css/styles.css', $actualResult); + $this->assertStringMatchesFormat( + 'http://localhost/pub/static/%s/frontend/%s/en_US/css/styles.css', + $actualResult + ); } public function testGetModuleName() diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Element/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Element/TemplateTest.php index 050b53818ce57..6e078b491955d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Element/TemplateTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Element/TemplateTest.php @@ -1,10 +1,12 @@ assertEquals('frontend', $this->_block->getArea()); \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( \Magento\Framework\App\State::class - )->setAreaCode( - 'some_area' - ); - $this->assertEquals('some_area', $this->_block->getArea()); + )->setAreaCode(Area::AREA_ADMINHTML); + $this->assertEquals(Area::AREA_ADMINHTML, $this->_block->getArea()); \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( \Magento\Framework\App\State::class - )->setAreaCode( - 'another_area' - ); - $this->assertEquals('another_area', $this->_block->getArea()); + )->setAreaCode(Area::AREA_GLOBAL); + $this->assertEquals(Area::AREA_GLOBAL, $this->_block->getArea()); } /** @@ -71,7 +69,7 @@ public function testGetArea() public function testToHtml() { \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\App\State::class) - ->setAreaCode('any area'); + ->setAreaCode(Area::AREA_GLOBAL); $this->assertEmpty($this->_block->toHtml()); $this->_block->setTemplate(uniqid('invalid_filename.phtml')); $this->assertEmpty($this->_block->toHtml()); diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Element/Text/ListTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Element/Text/ListTest.php index c0750f8a8d27c..e48c1ebf33ad3 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Element/Text/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Element/Text/ListTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->registerThemes(); + $this->objectManager->addSharedInstance( + $this->objectManager->create( + \Magento\Framework\App\Arguments\ValidationState::class, + ['appMode' => 'default'] + ), + \Magento\Framework\App\Arguments\ValidationState::class + ); + $this->model = $this->objectManager->create( + \Magento\Framework\View\Element\UiComponent\Config\Provider\Template::class + ); + } + + public function testGetTemplate() + { + $expected = file_get_contents(__DIR__ . '/../../../../_files/UiComponent/expected/config.xml'); + + \Magento\TestFramework\Helper\Bootstrap::getInstance()->loadArea('adminhtml'); + $this->objectManager->get(\Magento\Framework\View\DesignInterface::class) + ->setDesignTheme('FrameworkViewUiComponent/default'); + CacheCleaner::cleanAll(); + + $resultOne = $this->model->getTemplate('test.xml'); + $resultTwo = $this->model->getTemplate('test.xml'); + + $this->assertXmlStringEqualsXmlString($expected, $resultOne); + $this->assertXmlStringEqualsXmlString($expected, $resultTwo); + } + + /** + * Register themes in the fixture folder + */ + protected function registerThemes() + { + /** @var \Magento\Theme\Model\Theme\Registration $registration */ + $registration = $this->objectManager->get( + \Magento\Theme\Model\Theme\Registration::class + ); + $registration->register(); + } + + protected function tearDown() + { + $this->objectManager->removeSharedInstance( + \Magento\Framework\App\Arguments\ValidationState::class + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Element/_files/frontend/Magento/plushe/css/wrong.css b/dev/tests/integration/testsuite/Magento/Framework/View/Element/_files/frontend/Magento/plushe/css/wrong.css index 575bd8dfe7c0a..45d1061b3f398 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Element/_files/frontend/Magento/plushe/css/wrong.css +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Element/_files/frontend/Magento/plushe/css/wrong.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ .test {background: url(../images/nonexistent_file.png);} diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/FileSystemTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/FileSystemTest.php index 3cf9c65d0db85..6c7eef060a18b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/FileSystemTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/FileSystemTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/Reader/_files/_layout_update_reference.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/Reader/_files/_layout_update_reference.xml index b20db4d3f6058..2a927145f66ef 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/Reader/_files/_layout_update_reference.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/Reader/_files/_layout_update_reference.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml index 4f70de9f07fbd..38824b4440127 100755 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_files/_layout_update.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_default.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_default.xml index 74ff6184c6237..a7b3e2fd8579c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_default.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_default.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_layered.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_layered.xml index 74ff6184c6237..a7b3e2fd8579c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_layered.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_category_layered.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view.xml index 7a8645ccd50be..6d6579aa0f632 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_configurable.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_configurable.xml index ee8f136931705..b42a03ded39bc 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_configurable.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_configurable.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_simple.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_simple.xml index 74ff6184c6237..a7b3e2fd8579c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_simple.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/catalog_product_view_type_simple.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/checkout_index_index.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/checkout_index_index.xml index 74ff6184c6237..a7b3e2fd8579c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/checkout_index_index.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/checkout_index_index.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/customer_account.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/customer_account.xml index b53759286abeb..b1124c0fe2a8a 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/customer_account.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/customer_account.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/default.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/default.xml index e4547573e5528..136affedd9d7f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/default.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/default.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/file_wrong.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/file_wrong.xml index 929b7f2011648..d143a05c54a38 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/file_wrong.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/file_wrong.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_one.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_one.xml index e6b2e77f1dd68..c655fa67e1086 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_one.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_one.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_page_layout.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_page_layout.xml index ff01b01ecd7bd..31ebcc935d30c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_page_layout.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_page_layout.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_two.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_two.xml index 1b9356ff53918..96c5bae8837da 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_two.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_two.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_with_page_layout.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_with_page_layout.xml index d3d5f6500bb42..2759347d00434 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_with_page_layout.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/fixture_handle_with_page_layout.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/not_a_page_type.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/not_a_page_type.xml index 2b5ce0242070d..e02af2526be51 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/not_a_page_type.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/not_a_page_type.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/page_empty.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/page_empty.xml index 125e66cab3a2f..a9ef8190ea3b3 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/page_empty.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/page_empty.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/print.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/print.xml index 74ff6184c6237..a7b3e2fd8579c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/print.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/print.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_guest_print.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_guest_print.xml index 74ff6184c6237..a7b3e2fd8579c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_guest_print.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_guest_print.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_order_print.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_order_print.xml index 74ff6184c6237..a7b3e2fd8579c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_order_print.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/layout/sales_order_print.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/merged.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/merged.xml index cc191e44edaa7..36cf76075b737 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/merged.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Layout/_mergeFiles/merged.xml @@ -3,7 +3,7 @@ /** * Layout instructions merged from sibling XML files. To be used as an expectation for a test. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutArgumentObjectUpdater.php b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutArgumentObjectUpdater.php index 8e5fb1dad9efe..b1c41262806fd 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutArgumentObjectUpdater.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutArgumentObjectUpdater.php @@ -1,6 +1,6 @@ assertTrue($layout->isBlock('child_block2')); } + /** + * @magentoAppIsolation enabled + */ + public function testRemoveCancellation() + { + $layout = $this->_getLayoutModel('remove_cancellation.xml'); + $this->assertTrue($layout->isContainer('container1')); + $this->assertTrue($layout->isBlock('child_block1')); + $this->assertTrue($layout->isBlock('no_name2')); + $this->assertFalse($layout->getBlock('not_exist')); + } + /** * @magentoAppIsolation enabled */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutTest.php index 27b3c322a9904..430f21473a8bd 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/LayoutTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/LayoutTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Model/Layout/_files/layout/fixture_handle_two.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Model/Layout/_files/layout/fixture_handle_two.xml index 1b9356ff53918..96c5bae8837da 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Model/Layout/_files/layout/fixture_handle_two.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Model/Layout/_files/layout/fixture_handle_two.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Page/Config/Reader/HtmlTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Page/Config/Reader/HtmlTest.php index d3df108a948f9..d8f12e1877ed8 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Page/Config/Reader/HtmlTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Page/Config/Reader/HtmlTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/Layout.php b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/Layout.php index 3ca48a803a397..9bb6d2f37d506 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/Layout.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/Layout.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_three.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_three.xml index 1b15509585a7d..a7510a00e9f70 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_three.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_three.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_two.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_two.xml index 3701a68d70f09..a4982f1b83386 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_two.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout/handle_two.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/multiple_handles.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/multiple_handles.xml index 5f605d68464e6..63efb0bd689eb 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/multiple_handles.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/multiple_handles.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/single_handle.xml b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/single_handle.xml index 3f38cc480faea..dd578eb539f4c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/single_handle.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Utility/_files/layout_merged/single_handle.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/Fixture_Module/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/Fixture_Module/registration.php index 5c038cd2c2240..69601f23c2b46 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/Fixture_Module/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/Fixture_Module/registration.php @@ -1,6 +1,6 @@ + +
    + + + Magento\Catalog\Block\Adminhtml\Product\Edit\Button\CreateCategory + + + new_category_form.new_category_form_data_source + + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/Magento_Catalog/ui_component/test.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/Magento_Catalog/ui_component/test.xml new file mode 100644 index 0000000000000..184b62d4cbf87 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/Magento_Catalog/ui_component/test.xml @@ -0,0 +1,14 @@ + + +
    + + + new_category_form.new_category_form_data_source + + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/Magento_Customer/ui_component/test.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/Magento_Customer/ui_component/test.xml new file mode 100644 index 0000000000000..4beb5dfbd451b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/Magento_Customer/ui_component/test.xml @@ -0,0 +1,14 @@ + + +
    + + + Magento\Catalog\Block\Adminhtml\Product\Edit\Button\CreateCategory + + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/registration.php new file mode 100644 index 0000000000000..6adce6526e393 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/UiComponent/theme/registration.php @@ -0,0 +1,11 @@ + + + Test theme + diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/app/code/ViewTest_Module/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/app/code/ViewTest_Module/registration.php index 2f676abde92c6..7c93437ab3eef 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/app/code/ViewTest_Module/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/app/code/ViewTest_Module/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/ViewTest_Module/web/fixture_script_two.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/ViewTest_Module/web/fixture_script_two.js index fa637bc53d9d1..d2b7558e01694 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/ViewTest_Module/web/fixture_script_two.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/ViewTest_Module/web/fixture_script_two.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Modular file in package/custom_theme */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/registration.php index ff4f232e03e22..72400c12b992b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/theme.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/theme.xml index f9a5d0aa25c58..fa686cbf67188 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/theme.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/theme.xml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/fixture_script_two.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/fixture_script_two.js index aaf3a2ade6a58..b332b37f5eb6e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/fixture_script_two.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/fixture_script_two.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Non-modular file in package/custom_theme */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/mage/script.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/mage/script.js index a227df805914f..e96d9aa2b313e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/mage/script.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme/web/mage/script.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Non-modular file in package/custom_theme, which overrides js lib file */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme2/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme2/registration.php index b7a57ae2182b1..a18b26d7c0d93 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme2/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/custom_theme2/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/templates/fixture_template.phtml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/templates/fixture_template.phtml index 508b7ada92753..560faedecb55c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/templates/fixture_template.phtml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/templates/fixture_template.phtml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/fixture_script.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/fixture_script.js index 13e0a28141185..67b7ef68db026 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/fixture_script.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/fixture_script.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Modular file in package/default */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/i18n/ru_RU/fixture_script.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/i18n/ru_RU/fixture_script.js index 9cff851527d81..55889017f1e6c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/i18n/ru_RU/fixture_script.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/ViewTest_Module/web/i18n/ru_RU/fixture_script.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Localized modular file in package/default */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/registration.php index a297b331d8cfe..90edc63995ccc 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/theme.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/theme.xml index d4f697626622d..6aab4dfcfbca9 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/theme.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/theme.xml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/fixture_script.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/fixture_script.js index bf6a43e0f770e..9a68e3060e602 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/fixture_script.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/fixture_script.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Non-modular file in package/default */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/i18n/ru_RU/fixture_script.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/i18n/ru_RU/fixture_script.js index ea398b1c9808e..c3651a11a1091 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/i18n/ru_RU/fixture_script.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/default/web/i18n/ru_RU/fixture_script.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Localized non-modular file in package/default */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/standalone_theme/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/standalone_theme/registration.php index c8eb0413a3b60..f738ea28bbaac 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/standalone_theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/design/frontend/Vendor/standalone_theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/lib/web/mage/script.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/lib/web/mage/script.js index 35e12e040fd55..09b5789dbc585 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/lib/web/mage/script.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/fallback/lib/web/mage/script.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* Fixture js lib file */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/cacheable.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/cacheable.xml index b1028375b89d9..c4625856a17e8 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/cacheable.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/cacheable.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/container_attributes.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/container_attributes.xml index 7b7b85ad512da..c195736bd253d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/container_attributes.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/container_attributes.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/non_cacheable.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/non_cacheable.xml index 60278a7bbadb9..c6667dc457ac2 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/non_cacheable.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout/non_cacheable.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/action_for_anonymous_parent_block.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/action_for_anonymous_parent_block.xml index d1051752d8256..bc33ad6446614 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/action_for_anonymous_parent_block.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/action_for_anonymous_parent_block.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments.xml index 2e9bb811ce9d7..651e21d1ab919 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_complex_values.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_complex_values.xml index ee81df607f828..49f03c7dfe641 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_complex_values.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_complex_values.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type.xml index 0ede25c408f29..13bb50cb4d865 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type_updaters.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type_updaters.xml index 595dcaea9a1a8..bb203b2bc79a6 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type_updaters.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_object_type_updaters.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_url_type.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_url_type.xml index 482d8ed3926ff..ecda283f74b20 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_url_type.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/arguments_url_type.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/get_block.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/get_block.xml index bce6855483a6a..d43f1242fb6ee 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/get_block.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/get_block.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml index 1008e2f1b6108..c1635efd5c976 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/group.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/ifconfig.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/ifconfig.xml index 0578c6d3f3821..f2248b4e2078c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/ifconfig.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/ifconfig.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move.xml index f5f496a832155..670e4738826e6 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_alias_broken.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_alias_broken.xml index deddd9a79c606..40527a81072eb 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_alias_broken.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_alias_broken.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_broken.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_broken.xml index d17c5a5e64398..7a141b4530ce7 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_broken.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_broken.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_new_alias.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_new_alias.xml index 0c3a21a47cb68..d8a41c825c6f8 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_new_alias.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_new_alias.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_the_same_alias.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_the_same_alias.xml index 9a599b3762a89..b68a9aba07996 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_the_same_alias.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/move_the_same_alias.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml index 079e2eb9ce8f9..49e740eaf1d32 100755 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml index 488ea746028e3..a3b487f3e356c 100755 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_broken.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_cancellation.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_cancellation.xml new file mode 100644 index 0000000000000..4fbba07e0d150 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/remove_cancellation.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/render.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/render.xml index 4b65bb191728f..174f4d19b69af 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/render.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/render.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_after.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_after.xml index 65e91299bf087..6dcd4c8298f59 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_after.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_after.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_previous.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_previous.xml index c4e81d1ad5c19..5d50646c4873e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_previous.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_after_previous.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_after.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_after.xml index 0dcd9597d76c2..54f6eeab9ad85 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_after.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_after.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_before.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_before.xml index 7651489783a2c..ed8756bda0c1a 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_before.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_directives_test/sort_before_before.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_with_exceptions/layout.xml b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_with_exceptions/layout.xml index 7de1a41973883..8e16407d0b96a 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_with_exceptions/layout.xml +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/layout_with_exceptions/layout.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/registration.php b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/registration.php index 40db3f5706ebd..db6625a572145 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/preminified-styles.min.css b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/preminified-styles.min.css index bd4689ffec123..5f655721d8764 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/preminified-styles.min.css +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/preminified-styles.min.css @@ -1,9 +1,9 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* * Magento/backend * semi-minified file to check that .min.css files are not minified with library */ -table > caption { margin-bottom: 5px;}table thead { background: #676056; color: #f7f3eb;}table thead .headings { background: #807a6e;} \ No newline at end of file +table > caption { margin-bottom: 5px;}table thead { background: #676056; color: #f7f3eb;}table thead .headings { background: #807a6e;} diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/styles.css b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/styles.css index add24e8e3e0bb..7b6ef6e3f8076 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/styles.css +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/css/styles.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* FrameworkViewMinifier/frontend */ @@ -1450,7 +1450,7 @@ fieldset[disabled] .pager .action-next { margin-bottom: 25px; } /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ .sales-order-create-index .order-errors .notice { diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/js/test.js b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/js/test.js index a3f4ad36d0afa..75d9a90c305b7 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/js/test.js +++ b/dev/tests/integration/testsuite/Magento/Framework/View/_files/static/theme/web/js/test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/integration/testsuite/Magento/GiftMessage/Model/OrderItemRepositoryTest.php b/dev/tests/integration/testsuite/Magento/GiftMessage/Model/OrderItemRepositoryTest.php index bb6729974c992..580b566605a52 100644 --- a/dev/tests/integration/testsuite/Magento/GiftMessage/Model/OrderItemRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/GiftMessage/Model/OrderItemRepositoryTest.php @@ -1,6 +1,6 @@ assertEquals($data[$productId]['qty'], $product->getQty()); $this->assertEquals($data[$productId]['position'], $product->getPosition()); } + + /** + * @magentoDataFixture Magento/GroupedProduct/_files/product_grouped.php + * @magentoAppIsolation enabled + * @magentoDbIsolation disabled + */ + public function testPrepareProduct() + { + $buyRequest = $this->objectManager->create( + \Magento\Framework\DataObject::class, + ['data' => ['value' => ['qty' => 2]]] + ); + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $product = $productRepository->get('grouped-product'); + + /** @var \Magento\GroupedProduct\Model\Product\Type\Grouped $type */ + $type = $this->objectManager->get(\Magento\GroupedProduct\Model\Product\Type\Grouped::class); + + $processModes = [ + \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_FULL, + \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_LITE + ]; + $expectedData = [ + \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_FULL => [ + 1 => '{"super_product_config":{"product_type":"grouped","product_id":"' + . $product->getId() . '"}}', + 21 => '{"super_product_config":{"product_type":"grouped","product_id":"' + . $product->getId() . '"}}', + ], + \Magento\GroupedProduct\Model\Product\Type\Grouped::PROCESS_MODE_LITE => [ + $product->getId() => '{"value":{"qty":2}}', + ] + ]; + + foreach ($processModes as $processMode) { + $products = $type->processConfiguration($buyRequest, $product, $processMode); + foreach ($products as $item) { + $productId = $item->getId(); + $this->assertEquals( + $expectedData[$processMode][$productId], + $item->getCustomOptions()['info_buyRequest']->getValue(), + "Wrong info_buyRequest data for product with id: $productId" + ); + } + } + } } diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/ResourceModel/Product/Type/Grouped/AssociatedProductsCollectionTest.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/ResourceModel/Product/Type/Grouped/AssociatedProductsCollectionTest.php index 5f267cdd6b091..ae7555bf96635 100644 --- a/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/ResourceModel/Product/Type/Grouped/AssociatedProductsCollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/Model/ResourceModel/Product/Type/Grouped/AssociatedProductsCollectionTest.php @@ -1,6 +1,6 @@ ['entity' => 'entity', 'file_format' => 'file_format']]; + protected $_expectedFields = ['base_fieldset' => [ + 'entity' => 'entity', + 'file_format' => 'file_format', + 'fields_enclosure' => 'fields_enclosure' + ]]; protected function setUp() { diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Block/Adminhtml/Export/FilterTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Block/Adminhtml/Export/FilterTest.php index 0901a7a0e647a..d21f463f1e8e9 100644 --- a/dev/tests/integration/testsuite/Magento/ImportExport/Block/Adminhtml/Export/FilterTest.php +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Block/Adminhtml/Export/FilterTest.php @@ -1,6 +1,6 @@ getResponse()->getBody(); $this->assertSelectCount('fieldset#base_fieldset', 1, $body); - $this->assertSelectCount('fieldset#base_fieldset div.field', 2, $body); + $this->assertSelectCount('fieldset#base_fieldset div.field', 3, $body); } } diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/HttpFactoryMock.php b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/HttpFactoryMock.php index bb3e54ca1578f..2204e09adc49c 100644 --- a/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/HttpFactoryMock.php +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Controller/Adminhtml/Import/HttpFactoryMock.php @@ -1,6 +1,6 @@ getAttributeCode() == $indexAttributeCode ? 'value' : 'label'; $expectedOptions = []; foreach ($attribute->getSource()->getAllOptions(false) as $option) { - $expectedOptions[strtolower($option[$index])] = $option['value']; + if (is_array($option['value'])) { + foreach ($option['value'] as $value) { + $expectedOptions[strtolower($value[$index])] = $value['value']; + } + } else { + $expectedOptions[strtolower($option[$index])] = $option['value']; + } } $actualOptions = $this->_model->getAttributeOptions($attribute, [$indexAttributeCode]); - sort($expectedOptions); - sort($actualOptions); + asort($expectedOptions); + asort($actualOptions); $this->assertEquals($expectedOptions, $actualOptions); } } diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php index 31eee1f4f5f63..81862673da75a 100644 --- a/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Model/Import/EntityAbstractTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php b/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php index fc3d466dd499b..62faa71a98695 100644 --- a/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php +++ b/dev/tests/integration/testsuite/Magento/Indexer/Model/Config/_files/result.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integrationB.xml b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integrationB.xml index 50d97b5199b28..75abf8684e4d0 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integrationB.xml +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integrationB.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/ReaderTest.php index d8fd8dcbbd6f5..c59cb394f1d9d 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/ReaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/ReaderTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/_files/apiB.xml b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/_files/apiB.xml index 86f35e766ddd7..197fadc9242d5 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/_files/apiB.xml +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Integration/_files/apiB.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/ReaderTest.php index 04027282846c0..3f5ba35b710cf 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/ReaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/ReaderTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/configB.xml b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/configB.xml index bc7cd37b388b5..9c618f8ece24a 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/configB.xml +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/configB.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/integration.php b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/integration.php index fcab6864dc213..a1e26c973f320 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/integration.php +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/_files/integration.php @@ -1,6 +1,6 @@ markTestSkipped("For HHVM it's not relevant while MAGETWO-33679 is not resolved"); + $this->markTestSkipped("Test not relevant because no gc in HHVM."); } $this->_helper = new \Magento\TestFramework\Helper\Memory( new \Magento\Framework\Shell(new \Magento\Framework\Shell\CommandRenderer()) @@ -32,7 +32,7 @@ protected function setUp() */ public function testAppReinitializationNoMemoryLeak() { - $this->markTestSkipped('Test fails at Travis. Skipped in scope of MAGETWO-48538'); + $this->markTestSkipped('Test fails at Travis. Skipped until MAGETWO-47111'); $this->_deallocateUnusedMemory(); $actualMemoryUsage = $this->_helper->getRealMemoryUsage(); diff --git a/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/Address/SelectTest.php b/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/Address/SelectTest.php index 934017f9adc75..47fd3f841596c 100644 --- a/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/Address/SelectTest.php +++ b/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/Address/SelectTest.php @@ -1,6 +1,6 @@ get(\Magento\Framework\App\ResourceConnection::class); +$connection = $resource->getConnection(); +$resourceModel = $objectManager->create(\Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate::class); +$entityTable = $resourceModel->getTable('shipping_tablerate'); +$data = + [ + 'website_id' => 1, + 'dest_country_id' => 'US', + 'dest_region_id' => 0, + 'dest_zip' => '*', + 'condition_name' => 'package_qty', + 'condition_value' => 1, + 'price' => 10, + 'cost' => 10 + ]; +$connection->query( + "INSERT INTO {$entityTable} (`website_id`, `dest_country_id`, `dest_region_id`, `dest_zip`, `condition_name`," + . "`condition_value`, `price`, `cost`) VALUES (:website_id, :dest_country_id, :dest_region_id, :dest_zip," + . " :condition_name, :condition_value, :price, :cost);", + $data +); diff --git a/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates_rollback.php b/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates_rollback.php new file mode 100644 index 0000000000000..2966a797c9473 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/OfflineShipping/_files/tablerates_rollback.php @@ -0,0 +1,12 @@ +get(\Magento\Framework\App\ResourceConnection::class); +$connection = $resource->getConnection(); +$resourceModel = $objectManager->create(\Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate::class); +$entityTable = $resourceModel->getTable('shipping_tablerate'); +$connection->query("DELETE FROM {$entityTable};"); diff --git a/dev/tests/integration/testsuite/Magento/PageCache/Block/JavascriptTest.php b/dev/tests/integration/testsuite/Magento/PageCache/Block/JavascriptTest.php index f02bed642a956..22a44e33fc926 100644 --- a/dev/tests/integration/testsuite/Magento/PageCache/Block/JavascriptTest.php +++ b/dev/tests/integration/testsuite/Magento/PageCache/Block/JavascriptTest.php @@ -1,6 +1,6 @@ dispatch('backend/admin/system_config/edit/section/system/'); $body = $this->getResponse()->getBody(); - $this->assertContains('system_full_page_cache_varnish_export_button_version3', $body); $this->assertContains('system_full_page_cache_varnish_export_button_version4', $body); + $this->assertContains('system_full_page_cache_varnish_export_button_version5', $body); $this->assertContains('[id^=system_full_page_cache_varnish_export_button_version]', $body); } } diff --git a/dev/tests/integration/testsuite/Magento/PageCache/Model/ConfigTest.php b/dev/tests/integration/testsuite/Magento/PageCache/Model/ConfigTest.php new file mode 100644 index 0000000000000..7c0e561a9742a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/PageCache/Model/ConfigTest.php @@ -0,0 +1,67 @@ +getMock( + \Magento\Framework\Filesystem\Directory\ReadFactory::class, + [], + [], + '', + false + ); + $modulesDirectoryMock = $this->getMock( + \Magento\Framework\Filesystem\Directory\Write::class, + [], + [], + '', + false + ); + $readFactoryMock->expects( + $this->any() + )->method( + 'create' + )->will( + $this->returnValue($modulesDirectoryMock) + ); + $modulesDirectoryMock->expects( + $this->any() + )->method( + 'readFile' + )->will( + $this->returnValue(file_get_contents(__DIR__ . '/_files/test.vcl')) + ); + $this->config = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\PageCache\Model\Config::class, + [ + 'readFactory' => $readFactoryMock + ] + ); + } + + // @codingStandardsIgnoreStart + /** + * @magentoConfigFixture default/system/full_page_cache/varnish/backend_host example.com + * @magentoConfigFixture default/system/full_page_cache/varnish/backend_port 8080 + * @magentoConfigFixture default/system/full_page_cache/varnish/access_list 127.0.0.1,192.168.0.1,127.0.0.2 + * @magentoConfigFixture current_store design/theme/ua_regexp {"_":{"regexp":"\/firefox\/i","value":"Magento\/blank"}} + * @magentoAppIsolation enabled + */ + // @codingStandardsIgnoreEnd + public function testGetVclFile() + { + $result = $this->config->getVclFile(Config::VARNISH_5_CONFIGURATION_PATH); + $this->assertEquals(file_get_contents(__DIR__ . '/_files/result.vcl'), $result); + } +} diff --git a/dev/tests/integration/testsuite/Magento/PageCache/Model/Layout/MergeTest.php b/dev/tests/integration/testsuite/Magento/PageCache/Model/Layout/MergeTest.php new file mode 100644 index 0000000000000..bdc82b2ab0875 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/PageCache/Model/Layout/MergeTest.php @@ -0,0 +1,37 @@ +getMock(\Magento\Framework\Cache\FrontendInterface::class); + /** @var \Magento\Framework\View\Model\Layout\Merge $layoutMerge */ + $layoutMerge = $objectManager->create( + \Magento\Framework\View\Model\Layout\Merge::class, + ['cache' => $cacheMock] + ); + + /** @var EntitySpecificHandlesList $entitySpecificHandleList */ + $entitySpecificHandleList = $objectManager->get(EntitySpecificHandlesList::class); + // Add 'default' handle, which has declarations of blocks with ttl, to the list of entity specific handles. + // This allows to simulate a situation, when block with ttl attribute + // is declared e.g. in 'catalog_product_view_id_1' handle + $entitySpecificHandleList->addHandle('default'); + $layoutMerge->load(['default']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/PageCache/Model/System/Config/Backend/TtlTest.php b/dev/tests/integration/testsuite/Magento/PageCache/Model/System/Config/Backend/TtlTest.php index 1148f2ec6b8ee..97f0656f42b28 100644 --- a/dev/tests/integration/testsuite/Magento/PageCache/Model/System/Config/Backend/TtlTest.php +++ b/dev/tests/integration/testsuite/Magento/PageCache/Model/System/Config/Backend/TtlTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Payment/Model/_files/payment2.xml b/dev/tests/integration/testsuite/Magento/Payment/Model/_files/payment2.xml index 6c448abdb95ff..d77f7b23ed2ff 100644 --- a/dev/tests/integration/testsuite/Magento/Payment/Model/_files/payment2.xml +++ b/dev/tests/integration/testsuite/Magento/Payment/Model/_files/payment2.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Payment/Observer/UpdateOrderStatusForPaymentMethodsObserverTest.php b/dev/tests/integration/testsuite/Magento/Payment/Observer/UpdateOrderStatusForPaymentMethodsObserverTest.php index 8a3f4746ed006..065eea3feb69a 100644 --- a/dev/tests/integration/testsuite/Magento/Payment/Observer/UpdateOrderStatusForPaymentMethodsObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/Payment/Observer/UpdateOrderStatusForPaymentMethodsObserverTest.php @@ -1,6 +1,6 @@ @@ -28,12 +28,12 @@ paypal-top-section paypal-other-header - Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded + \Magento\Config\Block\System\Config\Form\Fieldset paypal-top-section payments-other-header - Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded + \Magento\Config\Block\System\Config\Form\Fieldset
    diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml index 9dc77b836656a..fd8771e8aad99 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml @@ -1,7 +1,7 @@ @@ -28,12 +28,12 @@ paypal-top-section paypal-other-header - Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded + \Magento\Config\Block\System\Config\Form\Fieldset paypal-top-section payments-other-header - Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded + \Magento\Config\Block\System\Config\Form\Fieldset
    @@ -115,7 +115,7 @@ - + Magento\Config\Model\Config\Source\Yesno payment/payflowpro_cc_vault/active 1 @@ -593,7 +593,8 @@ Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded - + + not-required Start accepting payments via PayPal!]]> diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Express/CheckoutTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/Express/CheckoutTest.php index c64500fa6cfec..085bd1f0ad108 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Express/CheckoutTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/Express/CheckoutTest.php @@ -1,6 +1,6 @@ loadArea('adminhtml'); +\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\App\Config\MutableScopeConfigInterface::class +)->setValue( + 'carriers/flatrate/active', + 1, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE +); +\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\App\Config\MutableScopeConfigInterface::class +)->setValue( + 'payment/paypal_express/active', + 1, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE +); +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId('simple') + ->setId(1) + ->setAttributeSetId(4) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData( + [ + 'qty' => 100, + 'is_in_stock' => 1, + ] + )->save(); +$product->load(1); + +$billingData = [ + 'firstname' => 'testname', + 'lastname' => 'lastname', + 'company' => '', + 'email' => 'test@com.com', + 'street' => [ + 0 => 'test1', + 1 => '', + ], + 'city' => 'Test', + 'region_id' => '1', + 'region' => '', + 'postcode' => '9001', + 'country_id' => 'US', + 'telephone' => '11111111', + 'fax' => '', + 'confirm_password' => '', + 'save_in_address_book' => '1', + 'use_for_shipping' => '1', +]; + +$billingAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Quote\Model\Quote\Address::class, ['data' => $billingData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); +$shippingAddress->setShippingMethod('flatrate_flatrate'); +$shippingAddress->setCollectShippingRates(true); + +/** @var $quote \Magento\Quote\Model\Quote */ +$quote = $objectManager->create(\Magento\Quote\Model\Quote::class); +$quote->setCustomerIsGuest( + true +)->setStoreId( + $objectManager->get( + \Magento\Store\Model\StoreManagerInterface::class + )->getStore()->getId() +)->setReservedOrderId( + '100000002' +)->setBillingAddress( + $billingAddress +)->setShippingAddress( + $shippingAddress +)->addProduct( + $product, + 10 +); +$quote->getShippingAddress()->setShippingMethod('flatrate_flatrate'); +$quote->getShippingAddress()->setCollectShippingRates(true); +$quote->getPayment()->setMethod(\Magento\Paypal\Model\Config::METHOD_WPS_EXPRESS); + +$quoteRepository = $objectManager->get(\Magento\Quote\Api\CartRepositoryInterface::class); +$quoteRepository->save($quote); +$quote = $quoteRepository->get($quote->getId()); +$quote->setCustomerEmail('admin@example.com'); diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_express_with_customer.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_express_with_customer.php new file mode 100644 index 0000000000000..396611b9d8a6a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_express_with_customer.php @@ -0,0 +1,77 @@ +loadArea('adminhtml'); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +$objectManager->get( + \Magento\Framework\App\Config\MutableScopeConfigInterface::class +)->setValue('carriers/flatrate/active', 1, \Magento\Store\Model\ScopeInterface::SCOPE_STORE); +$objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class) + ->setValue('payment/paypal_express/active', 1, \Magento\Store\Model\ScopeInterface::SCOPE_STORE); + +/** @var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); +$customer = $customerRepository->getById(1); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId('simple') + ->setId(1) + ->setAttributeSetId(4) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setStockData([ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 100, + ]) + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->save(); +$product->load(1); + +$customerBillingAddress = $objectManager->create(\Magento\Customer\Model\Address::class); +$customerBillingAddress->load(1); +$billingAddressDataObject = $customerBillingAddress->getDataModel(); +$billingAddress = $objectManager->create(\Magento\Quote\Model\Quote\Address::class); +$billingAddress->importCustomerAddressData($billingAddressDataObject); +$billingAddress->setAddressType('billing'); + +/** @var \Magento\Customer\Model\Address $customerShippingAddress */ +$customerShippingAddress = $objectManager->create(\Magento\Customer\Model\Address::class); +$customerShippingAddress->load(2); +$shippingAddressDataObject = $customerShippingAddress->getDataModel(); +$shippingAddress = $objectManager->create(\Magento\Quote\Model\Quote\Address::class); +$shippingAddress->importCustomerAddressData($shippingAddressDataObject); +$shippingAddress->setAddressType('shipping'); + +$shippingAddress->setShippingMethod('flatrate_flatrate'); +$shippingAddress->setCollectShippingRates(true); + +/** @var $quote \Magento\Quote\Model\Quote */ +$quote = $objectManager->create(\Magento\Quote\Model\Quote::class); +$quote->setCustomerIsGuest(false) + ->setCustomerId($customer->getId()) + ->setCustomer($customer) + ->setStoreId($objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore()->getId()) + ->setReservedOrderId('test02') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->addProduct($product, 10); +$quote->getShippingAddress()->setShippingMethod('flatrate_flatrate'); +$quote->getShippingAddress()->setCollectShippingRates(true); +$quote->getPayment()->setMethod(\Magento\Paypal\Model\Config::METHOD_WPS_EXPRESS); + +/** @var \Magento\Quote\Api\CartRepositoryInterface $quoteRepository */ +$quoteRepository = $objectManager->create(\Magento\Quote\Api\CartRepositoryInterface::class); +$quoteRepository->save($quote); +$quote = $quoteRepository->get($quote->getId()); diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment.php index a33c44b64cf40..c038387a95794 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment.php @@ -1,6 +1,6 @@ loadArea('adminhtml'); -\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class -)->setValue( - 'carriers/flatrate/active', - 1, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE -); -\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class -)->setValue( - 'payment/paypal_express/active', - 1, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE -); -$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); -/** @var $product \Magento\Catalog\Model\Product */ -$product = $objectManager->create(\Magento\Catalog\Model\Product::class); -$product->setTypeId('simple') - ->setId(1) - ->setAttributeSetId(4) - ->setName('Simple Product') - ->setSku('simple') - ->setPrice(10) - ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) - ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->setStockData( - [ - 'qty' => 100, - 'is_in_stock' => 1, - ] - )->save(); -$product->load(1); - -$billingData = [ - 'firstname' => 'testname', - 'lastname' => 'lastname', - 'company' => '', - 'email' => 'test@com.com', - 'street' => [ - 0 => 'test1', - 1 => '', - ], - 'city' => 'Test', - 'region_id' => '1', - 'region' => '', - 'postcode' => '9001', - 'country_id' => 'US', - 'telephone' => '11111111', - 'fax' => '', - 'confirm_password' => '', - 'save_in_address_book' => '1', - 'use_for_shipping' => '1', -]; - -$billingAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Quote\Model\Quote\Address::class, ['data' => $billingData]); -$billingAddress->setAddressType('billing'); - -$shippingAddress = clone $billingAddress; -$shippingAddress->setId(null)->setAddressType('shipping'); -$shippingAddress->setShippingMethod('flatrate_flatrate'); -$shippingAddress->setCollectShippingRates(true); - -/** @var $quote \Magento\Quote\Model\Quote */ -$quote = $objectManager->create(\Magento\Quote\Model\Quote::class); -$quote->setCustomerIsGuest( - true -)->setStoreId( - $objectManager->get( - \Magento\Store\Model\StoreManagerInterface::class - )->getStore()->getId() -)->setReservedOrderId( - '100000002' -)->setBillingAddress( - $billingAddress -)->setShippingAddress( - $shippingAddress -)->addProduct( - $product, - 10 -); -$quote->getShippingAddress()->setShippingMethod('flatrate_flatrate'); -$quote->getShippingAddress()->setCollectShippingRates(true); -$quote->getPayment()->setMethod(\Magento\Paypal\Model\Config::METHOD_WPS_EXPRESS); - -$quoteRepository = $objectManager->get(\Magento\Quote\Api\CartRepositoryInterface::class); -$quoteRepository->save($quote); -$quote = $quoteRepository->get($quote->getId()); -$quote->setCustomerEmail('admin@example.com'); +require __DIR__ . '/quote_express.php'; /** @var $service \Magento\Quote\Api\CartManagementInterface */ $service = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express_with_customer.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express_with_customer.php index 1c6793f05dea9..7c1135652dafc 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express_with_customer.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_express_with_customer.php @@ -1,81 +1,9 @@ loadArea('adminhtml'); - -$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - -$objectManager->get( - \Magento\Framework\App\Config\MutableScopeConfigInterface::class -)->setValue('carriers/flatrate/active', 1, \Magento\Store\Model\ScopeInterface::SCOPE_STORE); -$objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class) - ->setValue('payment/paypal_express/active', 1, \Magento\Store\Model\ScopeInterface::SCOPE_STORE); - -/** @var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */ -$customerRepository = $objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); -$customer = $customerRepository->getById(1); - -/** @var $product \Magento\Catalog\Model\Product */ -$product = $objectManager->create(\Magento\Catalog\Model\Product::class); -$product->setTypeId('simple') - ->setId(1) - ->setAttributeSetId(4) - ->setName('Simple Product') - ->setSku('simple') - ->setPrice(10) - ->setStockData([ - 'use_config_manage_stock' => 1, - 'qty' => 100, - 'is_qty_decimal' => 0, - 'is_in_stock' => 100, -]) - ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) - ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->save(); -$product->load(1); - -$customerBillingAddress = $objectManager->create(\Magento\Customer\Model\Address::class); -$customerBillingAddress->load(1); -$billingAddressDataObject = $customerBillingAddress->getDataModel(); -$billingAddress = $objectManager->create(\Magento\Quote\Model\Quote\Address::class); -$billingAddress->importCustomerAddressData($billingAddressDataObject); -$billingAddress->setAddressType('billing'); - -/** @var \Magento\Customer\Model\Address $customerShippingAddress */ -$customerShippingAddress = $objectManager->create(\Magento\Customer\Model\Address::class); -$customerShippingAddress->load(2); -$shippingAddressDataObject = $customerShippingAddress->getDataModel(); -$shippingAddress = $objectManager->create(\Magento\Quote\Model\Quote\Address::class); -$shippingAddress->importCustomerAddressData($shippingAddressDataObject); -$shippingAddress->setAddressType('shipping'); - -$shippingAddress->setShippingMethod('flatrate_flatrate'); -$shippingAddress->setCollectShippingRates(true); - -/** @var $quote \Magento\Quote\Model\Quote */ -$quote = $objectManager->create(\Magento\Quote\Model\Quote::class); -$quote->setCustomerIsGuest(false) - ->setCustomerId($customer->getId()) - ->setCustomer($customer) - ->setStoreId($objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore()->getId()) - ->setReservedOrderId('test02') - ->setBillingAddress($billingAddress) - ->setShippingAddress($shippingAddress) - ->addProduct($product, 10); -$quote->getShippingAddress()->setShippingMethod('flatrate_flatrate'); -$quote->getShippingAddress()->setCollectShippingRates(true); -$quote->getPayment()->setMethod(\Magento\Paypal\Model\Config::METHOD_WPS_EXPRESS); - -/** @var \Magento\Quote\Api\CartRepositoryInterface $quoteRepository */ -$quoteRepository = $objectManager->create(\Magento\Quote\Api\CartRepositoryInterface::class); -$quoteRepository->save($quote); -$quote = $quoteRepository->get($quote->getId()); +require __DIR__ . '/quote_express_with_customer.php'; /** @var $service \Magento\Quote\Api\CartManagementInterface */ $service = $objectManager->create(\Magento\Quote\Api\CartManagementInterface::class); diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_payflow.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_payflow.php index ca49cf51ab26d..eb03186383d8b 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_payflow.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_payment_payflow.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Persistent/Model/SessionTest.php b/dev/tests/integration/testsuite/Magento/Persistent/Model/SessionTest.php index db51d99c4e4ab..75d5105edd8d3 100644 --- a/dev/tests/integration/testsuite/Magento/Persistent/Model/SessionTest.php +++ b/dev/tests/integration/testsuite/Magento/Persistent/Model/SessionTest.php @@ -1,6 +1,6 @@ assertEquals($this->_quote->getId(), $this->_address->getQuoteId()); $this->assertEquals($customerAddressId, $this->_address->getCustomerAddressId()); } + + /** + * Tests + * + * @covers \Magento\Quote\Model\Quote\Address::setAppliedTaxes() + * @covers \Magento\Quote\Model\Quote\Address::getAppliedTaxes() + * @dataProvider dataProvider + * @param $taxes + * @param $expected + */ + public function testAppliedTaxes($taxes, $expected) + { + $this->_address->setAppliedTaxes($taxes); + + $this->assertSame($expected, $this->_address->getAppliedTaxes()); + } + + public function dataProvider() + { + return [ + ['test', 'test'], + [[123, true], [123, true]] + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/RepositoryTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/RepositoryTest.php index bcc4ad0d151db..5f221919d1c40 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/RepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/RepositoryTest.php @@ -1,6 +1,6 @@ 1 ]; } + + /** + * Test to verify that reserved_order_id will be changed if it already in used + * + * @magentoDataFixture Magento/Sales/_files/order.php + * @magentoDataFixture Magento/Quote/_files/empty_quote.php + */ + public function testReserveOrderId() + { + $objectManager = Bootstrap::getObjectManager(); + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $objectManager->create(\Magento\Quote\Model\Quote::class); + $quote->load('reserved_order_id', 'reserved_order_id'); + $quote->reserveOrderId(); + $this->assertEquals('reserved_order_id', $quote->getReservedOrderId()); + $quote->setReservedOrderId('100000001'); + $quote->reserveOrderId(); + $this->assertNotEquals('100000001', $quote->getReservedOrderId()); + } } diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/ResourceModel/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/ResourceModel/QuoteTest.php new file mode 100644 index 0000000000000..1456f7877f46e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/ResourceModel/QuoteTest.php @@ -0,0 +1,45 @@ +_resourceModel = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Quote\Model\ResourceModel\Quote::class + ); + } + + /** + * Test to verify if isOrderIncrementIdUsed method works with numeric increment ids + * + * @magentoDataFixture Magento/Sales/_files/order.php + */ + public function testIsOrderIncrementIdUsedNumericIncrementId() + { + $this->assertTrue($this->_resourceModel->isOrderIncrementIdUsed('100000001')); + } + + /** + * Test to verify if isOrderIncrementIdUsed method works with alphanumeric increment ids + * + * @magentoDataFixture Magento/Sales/_files/order_alphanumeric_id.php + */ + public function testIsOrderIncrementIdUsedAlphanumericIncrementId() + { + $this->assertTrue($this->_resourceModel->isOrderIncrementIdUsed('M00000001')); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php new file mode 100644 index 0000000000000..33ae308c76ff3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php @@ -0,0 +1,95 @@ +executeTestFlow(0, 0); + } + + /** + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @magentoConfigFixture current_store carriers/tablerate/active 1 + * @magentoConfigFixture current_store carriers/tablerate/condition_name package_qty + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/OfflineShipping/_files/tablerates.php + */ + public function testEstimateByAddress() + { + $this->executeTestFlow(5, 10); + } + + /** + * Provide testing of shipping method estimation based on address + * + * @param int $flatRateAmount + * @param int $tableRateAmount + */ + private function executeTestFlow($flatRateAmount, $tableRateAmount) + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $objectManager->get(\Magento\Quote\Model\Quote::class); + $quote->load('test01', 'reserved_order_id'); + $cartId = $quote->getId(); + if (!$cartId) { + $this->fail('quote fixture failed'); + } + /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ + $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + ->create(); + $quoteIdMask->load($cartId, 'quote_id'); + //Use masked cart Id + $cartId = $quoteIdMask->getMaskedId(); + $data = [ + 'data' => [ + 'country_id' => "US", + 'postcode' => null, + 'region' => null, + 'region_id' => null + ] + ]; + /** @var \Magento\Quote\Api\Data\EstimateAddressInterface $address */ + $address = $objectManager->create(\Magento\Quote\Api\Data\EstimateAddressInterface::class, $data); + /** @var \Magento\Quote\Api\GuestShippingMethodManagementInterface $shippingEstimation */ + $shippingEstimation = $objectManager->get(\Magento\Quote\Api\GuestShippingMethodManagementInterface::class); + $result = $shippingEstimation->estimateByAddress($cartId, $address); + $this->assertNotEmpty($result); + $expectedResult = [ + 'tablerate' => + [ + 'method_code' => 'bestway', + 'amount' => $tableRateAmount + ], + 'flatrate' => [ + 'method_code' => 'flatrate', + 'amount' => $flatRateAmount + ] + ]; + foreach ($result as $rate) { + $this->assertEquals($expectedResult[$rate->getCarrierCode()]['amount'], $rate->getAmount()); + $this->assertEquals($expectedResult[$rate->getCarrierCode()]['method_code'], $rate->getMethodCode()); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php b/dev/tests/integration/testsuite/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php index 1a20ce3189f17..db6c5b96dcdcc 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Reports/Block/Adminhtml/Filter/FormTest.php b/dev/tests/integration/testsuite/Magento/Reports/Block/Adminhtml/Filter/FormTest.php index 9ce3f3eb8ae8c..dc0a83bd548dd 100644 --- a/dev/tests/integration/testsuite/Magento/Reports/Block/Adminhtml/Filter/FormTest.php +++ b/dev/tests/integration/testsuite/Magento/Reports/Block/Adminhtml/Filter/FormTest.php @@ -1,6 +1,6 @@ collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Reports\Model\ResourceModel\Product\Lowstock\Collection::class + ); + } + + /** + * Assert that filterByProductType method throws LocalizedException if not String or Array is passed to it + * + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testFilterByProductTypeException() + { + $this->collection->filterByProductType(100); + } + + /** + * Assert that String argument passed to filterByProductType method is correctly passed to attribute adder + * + */ + public function testFilterByProductTypeString() + { + $this->collection->filterByProductType('simple'); + $whereParts = $this->collection->getSelect()->getPart(\Magento\Framework\DB\Select::WHERE); + $this->assertContains('simple', $whereParts[0]); + } + + /** + * Assert that Array argument passed to filterByProductType method is correctly passed to attribute adder + * + */ + public function testFilterByProductTypeArray() + { + $this->collection->filterByProductType(['simple', 'configurable']); + $whereParts = $this->collection->getSelect()->getPart(\Magento\Framework\DB\Select::WHERE); + + $this->assertThat( + $whereParts[0], + $this->logicalAnd( + $this->stringContains('simple'), + $this->stringContains('configurable') + ) + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Reports/Model/ResourceModel/Report/Product/Viewed/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Reports/Model/ResourceModel/Report/Product/Viewed/CollectionTest.php index 4a06441a05007..2768f1543ccd0 100644 --- a/dev/tests/integration/testsuite/Magento/Reports/Model/ResourceModel/Report/Product/Viewed/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Reports/Model/ResourceModel/Report/Product/Viewed/CollectionTest.php @@ -1,6 +1,6 @@ getRequest()->setParam('id', $product->getId()); $this->dispatch('review/product/listAction'); $result = $this->getResponse()->getBody(); - $this->assertContains("static/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico", $result); + $this->assertContains("/frontend/Magento/blank/en_US/Magento_Theme/favicon.ico", $result); } } diff --git a/dev/tests/integration/testsuite/Magento/Review/Model/ResourceModel/Rating/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Review/Model/ResourceModel/Rating/CollectionTest.php index b59e81413b54d..6eb8699be7db9 100644 --- a/dev/tests/integration/testsuite/Magento/Review/Model/ResourceModel/Rating/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Review/Model/ResourceModel/Rating/CollectionTest.php @@ -1,6 +1,6 @@ assertNull($order->getShippingAddress()); } + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php + * @magentoDataFixture Magento/Downloadable/_files/order_with_downloadable_product_with_additional_options.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testInitFromOrderAndCreateOrderFromQuoteWithAdditionalOptions() + { + /** @var $serializer \Magento\Framework\Serialize\Serializer\Json */ + $serializer = Bootstrap::getObjectManager()->create(\Magento\Framework\Serialize\Serializer\Json::class); + + /** @var $order \Magento\Sales\Model\Order */ + $order = Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId('100000001'); + + /** @var $orderCreate \Magento\Sales\Model\AdminOrder\Create */ + $orderCreate = $this->_model->initFromOrder($order); + + $quoteItems = $orderCreate->getQuote()->getItemsCollection(); + + $this->assertEquals(1, $quoteItems->count()); + + $quoteItem = $quoteItems->getFirstItem(); + $quoteItemOptions = $quoteItem->getOptionsByCode(); + + $this->assertEquals( + $serializer->serialize(['additional_option_key' => 'additional_option_value']), + $quoteItemOptions['additional_options']->getValue() + ); + + $session = Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session\Quote::class); + $session->setCustomerId(1); + + $customer = Bootstrap::getObjectManager()->create(\Magento\Customer\Model\Customer::class); + $customer->load(1)->setDefaultBilling(null)->setDefaultShipping(null)->save(); + + $rate = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote\Address\Rate::class); + $rate->setCode('freeshipping_freeshipping'); + + $this->_model->getQuote()->getShippingAddress()->addShippingRate($rate); + $this->_model->setShippingAsBilling(0); + $this->_model->setPaymentData(['method' => 'checkmo']); + + $newOrder = $this->_model->createOrder(); + $newOrderItems = $newOrder->getItemsCollection(); + + $this->assertEquals(1, $newOrderItems->count()); + + $newOrderItem = $newOrderItems->getFirstItem(); + + $this->assertEquals( + ['additional_option_key' => 'additional_option_value'], + $newOrderItem->getProductOptionByCode('additional_options') + ); + } + /** * @magentoDataFixture Magento/Downloadable/_files/product_downloadable.php * @magentoDataFixture Magento/Downloadable/_files/order_with_downloadable_product.php @@ -451,9 +508,9 @@ public function testCreateOrderExistingCustomer() } /** - * @magentoAppIsolation enabled * @magentoDataFixture Magento/Sales/_files/quote.php * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoAppIsolation enabled */ public function testGetCustomerCartExistingCart() { @@ -477,6 +534,32 @@ public function testGetCustomerCartExistingCart() $this->assertSame($customerQuote, $customerQuoteFromCache, 'Customer quote caching does not work correctly.'); } + /** + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoAppIsolation enabled + */ + public function testMoveQuoteItemToCart() + { + $fixtureCustomerId = 1; + + /** Preconditions */ + /** @var \Magento\Backend\Model\Session\Quote $session */ + $session = Bootstrap::getObjectManager()->create(\Magento\Backend\Model\Session\Quote::class); + $session->setCustomerId($fixtureCustomerId); + /** @var $quoteFixture \Magento\Quote\Model\Quote */ + $quoteFixture = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); + $quoteFixture->load('test01', 'reserved_order_id'); + $quoteFixture->setCustomerIsGuest(false)->setCustomerId($fixtureCustomerId)->save(); + + $customerQuote = $this->_model->getCustomerCart(); + $item = $customerQuote->getAllVisibleItems()[0]; + + $this->_model->moveQuoteItem($item, 'cart', 3); + $this->assertEquals(4, $item->getQty(), 'Number of Qty isn\'t correct for Quote item.'); + $this->assertEquals(3, $item->getQtyToAdd(), 'Number of added qty isn\'t correct for Quote item.'); + } + /** * @magentoAppIsolation enabled * @magentoDbIsolation enabled diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Convert/OrderTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Convert/OrderTest.php index 30d0f23b27855..3596cbe8b8d53 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Convert/OrderTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Convert/OrderTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->orderAddressRenderer = $this->objectManager->get(OrderAddressRenderer::class); + $this->configResourceModel = $this->objectManager->get(ConfigResourceModel::class); + $this->config = $this->objectManager->get(Config::class); + } + + /** + * @magentoDataFixture Magento/Sales/_files/order_fixture_store.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testFormat() + { + $addressTemplates = [ + 'text' => 'text_customized', + 'oneline' => 'oneline_customized', + 'html' => 'html_customized', + 'pdf' => 'pdf_customized' + ]; + + /** @var Store $store */ + $store = $this->objectManager->create(Store::class); + $storeId = $store->load('fixturestore')->getStoreId(); + + $this->configResourceModel->saveConfig( + 'customer/address_templates/text', + $addressTemplates['text'], + 'stores', + $storeId + ); + $this->configResourceModel->saveConfig( + 'customer/address_templates/oneline', + $addressTemplates['oneline'], + 'stores', + $storeId + ); + $this->configResourceModel->saveConfig( + 'customer/address_templates/html', + $addressTemplates['html'], + 'stores', + $storeId + ); + $this->configResourceModel->saveConfig( + 'customer/address_templates/pdf', + $addressTemplates['pdf'], + 'stores', + $storeId + ); + $this->config->clean(); + + /** @var Order $order */ + $order = $this->objectManager->create(Order::class) + ->loadByIncrementId('100000004'); + + /** @var OrderAddress $address */ + $address = $order->getBillingAddress(); + + $this->assertEquals($addressTemplates['text'], $this->orderAddressRenderer->format($address, 'text')); + $this->assertEquals($addressTemplates['oneline'], $this->orderAddressRenderer->format($address, 'oneline')); + $this->assertEquals($addressTemplates['html'], $this->orderAddressRenderer->format($address, 'html')); + $this->assertEquals($addressTemplates['pdf'], $this->orderAddressRenderer->format($address, 'pdf')); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/AddressRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/AddressRepositoryTest.php index 687fff317ca50..3966678d57b36 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/AddressRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/AddressRepositoryTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoDataFixture Magento/Sales/_files/order_with_dummy_item_and_invoiced.php + * @dataProvider createByOrderDataProvider + * @param array $creditmemoData + * @param int $expectedQty + */ + public function testCreateByOrder(array $creditmemoData, $expectedQty) + { + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId('100000001'); + /** @var \Magento\Sales\Model\Order\CreditmemoFactory $creditmemoFactory */ + $creditmemoFactory = $this->objectManager->create(\Magento\Sales\Model\Order\CreditmemoFactory::class); + $creditmemoData = $this->prepareCreditMemoData($order, $creditmemoData); + $creditmemo = $creditmemoFactory->createByOrder($order, $creditmemoData); + $this->assertEquals($expectedQty, $creditmemo->getTotalQty(), 'Creditmemo has wrong total qty.'); + } + + /** + * Prepare Creditmemo data. + * + * @param \Magento\Sales\Model\Order $order + * @param array $creditmemoData + * @return array + */ + private function prepareCreditMemoData(\Magento\Sales\Model\Order $order, array $creditmemoData) + { + $result = []; + $orderItems = $order->getAllItems(); + foreach ($creditmemoData['qtys'] as $key => $item) { + $result[$orderItems[$this->prepareOrderItemKey($key)]->getId()] = $item; + } + $creditmemoData['qtys'] = $result; + + return $creditmemoData; + } + + /** + * Prepare order item key. + * + * @param string $key + * @return int + */ + private function prepareOrderItemKey($key) + { + return str_replace(self::ORDER_ITEM_ID_PLACEHOLDER, '', $key) - 1; + } + + /** + * @return array + */ + public function createByOrderDataProvider() + { + return [ + // Variation #1 + [ + //$creditmemoData + [ + 'qtys' => [ + self::ORDER_ITEM_ID_PLACEHOLDER . '1' => 1, + self::ORDER_ITEM_ID_PLACEHOLDER . '2' => 1, + ] + ], + //$expectedQty + 4 + ] + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Email/Sender/CreditmemoSenderTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Email/Sender/CreditmemoSenderTest.php index b2f24bc0e7c6a..eb28c431ff3b8 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Email/Sender/CreditmemoSenderTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Email/Sender/CreditmemoSenderTest.php @@ -1,6 +1,6 @@ get(\Magento\Sales\Model\Order\Item::class); + $model->setData('product_options', $options); + $this->assertEquals($expectedData, $model->getProductOptions()); + } + + /** + * @return array + */ + public function getProductOptionsDataProvider() + { + return [ + // Variation #1 + [ + // $options + '{"option1":1,"option2":2}', + //$expectedData + ["option1" => 1, "option2" => 2] + ], + // Variation #2 + [ + // $options + 'a:2:{s:7:"option1";i:1;s:7:"option2";i:2;}', + //$expectedData + null + ], + // Variation #3 + [ + // $options + ["option1" => 1, "option2" => 2], + //$expectedData + ["option1" => 1, "option2" => 2] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Payment/RepositoryTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Payment/RepositoryTest.php index 9d82e36478743..23c9e9f01bfd9 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Payment/RepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Payment/RepositoryTest.php @@ -1,6 +1,6 @@ get(IndexerRegistry::class) + ->get(FulltextIndexer::INDEXER_ID) + ->reindexAll(); + +require __DIR__ . '/../../Catalog/_files/product_simple_duplicated.php'; +/** @var Product $product */ -$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$addressData = include __DIR__ . '/address_data.php'; -$billingAddress = $objectManager->create(\Magento\Sales\Model\Order\Address::class, ['data' => $addressData]); +$billingAddress = $objectManager->create(OrderAddress::class, ['data' => $addressData]); $billingAddress->setAddressType('billing'); $shippingAddress = clone $billingAddress; $shippingAddress->setId(null)->setAddressType('shipping'); -$payment = $objectManager->create(\Magento\Sales\Model\Order\Payment::class); +$payment = $objectManager->create(OrderPayment::class); $payment->setMethod('checkmo'); -/** @var \Magento\Sales\Model\Order\Item $orderItem */ -$orderItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class); +/** @var OrderItem $orderItem */ +$orderItem = $objectManager->create(OrderItem::class); $orderItem->setProductId($product->getId())->setQtyOrdered(2); -/** @var \Magento\Sales\Model\Order $order */ -$order = $objectManager->create(\Magento\Sales\Model\Order::class); -$order->setIncrementId( - '100000004' -)->setState( - \Magento\Sales\Model\Order::STATE_PROCESSING -)->setStatus( - $order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_PROCESSING) -)->setSubtotal( - 100 -)->setBaseSubtotal( - 100 -)->setCustomerIsGuest( - true -)->setCustomerEmail( - 'customer@null.com' -)->setBillingAddress( - $billingAddress -)->setShippingAddress( - $shippingAddress -)->setStoreId( - $objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore('fixturestore')->getId() -)->addItem( - $orderItem -)->setPayment( - $payment -); +/** @var Order $order */ +$order = $objectManager->create(Order::class); +$order->setIncrementId('100000004') + ->setState(Order::STATE_PROCESSING) + ->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_PROCESSING)) + ->setSubtotal(100) + ->setBaseSubtotal(100) + ->setCustomerIsGuest(true) + ->setCustomerEmail('customer@null.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setStoreId($objectManager->get(StoreManagerInterface::class)->getStore('fixturestore')->getId()) + ->addItem($orderItem) + ->setPayment($payment); $order->save(); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_fixture_store_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_fixture_store_rollback.php new file mode 100644 index 0000000000000..5de1400aa1608 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_fixture_store_rollback.php @@ -0,0 +1,17 @@ +get(IndexerRegistry::class) + ->get(FulltextIndexer::INDEXER_ID) + ->reindexAll(); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php index 17b5652af2bd9..e7d6e66f99889 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_info.php @@ -1,6 +1,6 @@ 2, + \Magento\Sales\Api\Data\OrderItemInterface::BASE_PRICE => 100, + \Magento\Sales\Api\Data\OrderItemInterface::ORDER_ID => $order->getId(), + \Magento\Sales\Api\Data\OrderItemInterface::QTY_ORDERED => 2, + \Magento\Sales\Api\Data\OrderItemInterface::QTY_INVOICED => 2, + \Magento\Sales\Api\Data\OrderItemInterface::PRICE => 100, + \Magento\Sales\Api\Data\OrderItemInterface::ROW_TOTAL => 102, + \Magento\Sales\Api\Data\OrderItemInterface::PRODUCT_TYPE => 'bundle', + 'children' => [ + [ + \Magento\Sales\Api\Data\OrderItemInterface::PRODUCT_ID => 13, + \Magento\Sales\Api\Data\OrderItemInterface::ORDER_ID => $order->getId(), + \Magento\Sales\Api\Data\OrderItemInterface::QTY_ORDERED => 2, + \Magento\Sales\Api\Data\OrderItemInterface::QTY_INVOICED => 2, + \Magento\Sales\Api\Data\OrderItemInterface::BASE_PRICE => 90, + \Magento\Sales\Api\Data\OrderItemInterface::PRICE => 90, + \Magento\Sales\Api\Data\OrderItemInterface::ROW_TOTAL => 92, + \Magento\Sales\Api\Data\OrderItemInterface::PRODUCT_TYPE => 'simple', + 'product_options' => [ + 'bundle_selection_attributes' => '{"qty":2}', + ], + ] + ], + ] +]; + +// Invoiced all existing order items. +foreach ($order->getAllItems() as $item) { + $item->setQtyInvoiced(1); + $item->save(); +} + +saveOrderItems($orderItems); + + +/** + * Save Order Items. + * + * @param array $orderItems + * @param \Magento\Sales\Model\Order\Item|null $parentOrderItem [optional] + * @return void + */ +function saveOrderItems(array $orderItems, $parentOrderItem = null) +{ + /** @var array $orderItemData */ + foreach ($orderItems as $orderItemData) { + /** @var $orderItem \Magento\Sales\Model\Order\Item */ + $orderItem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Sales\Model\Order\Item::class + ); + if (null !== $parentOrderItem) { + $orderItemData['parent_item'] = $parentOrderItem; + } + $orderItem + ->setData($orderItemData) + ->save(); + + if (isset($orderItemData['children'])) { + saveOrderItems($orderItemData['children'], $orderItem); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice.php new file mode 100644 index 0000000000000..e346ab36cdab3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice.php @@ -0,0 +1,39 @@ +create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + +/** @var \Magento\Sales\Model\Service\InvoiceService $invoiceService */ +$invoiceService = $objectManager->create(\Magento\Sales\Api\InvoiceManagementInterface::class); + +/** @var \Magento\Framework\DB\Transaction $transaction */ +$transaction = $objectManager->create(\Magento\Framework\DB\Transaction::class); + +$order->setData( + 'base_to_global_rate', + 1 +)->setData( + 'base_to_order_rate', + 1 +)->setData( + 'shipping_amount', + 20 +)->setData( + 'base_shipping_amount', + 20 +); + +$invoice = $invoiceService->prepareInvoice($order); +$invoice->register(); + +$order->setIsInProcess(true); + +$transaction->addObject($invoice)->addObject($order)->save(); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice_rollback.php new file mode 100644 index 0000000000000..9d6603a14faf5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_shipping_and_invoice_rollback.php @@ -0,0 +1,6 @@ +loadArea('frontend'); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_rollback.php index 39afd0ba665c6..962d6e0d705d2 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_rollback.php @@ -1,6 +1,6 @@ loadArea('frontend'); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php index 7790636f2e36f..53d1c9738c699 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_bundle_rollback.php @@ -1,6 +1,6 @@ objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->cartManagement = $this->objectManager->get(\Magento\Quote\Api\GuestCartManagementInterface::class); + $this->itemRepository = $this->objectManager->get(\Magento\Quote\Api\GuestCartItemRepositoryInterface::class); + } + + /** + * @magentoDataFixture Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testRuleByProductWeightWithFreeShipping() + { + $cartId = $this->prepareQuote(1); + $methods = $this->estimateShipping($cartId); + + $this->assertTrue(count($methods) > 0); + $this->assertEquals('flatrate', $methods[0]->getMethodCode()); + $this->assertEquals(0, $methods[0]->getAmount()); + + } + + /** + * @magentoDataFixture Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + */ + public function testRuleByProductWeightWithoutFreeShipping() + { + $cartId = $this->prepareQuote(5); + $methods = $this->estimateShipping($cartId); + + $this->assertTrue(count($methods) > 0); + $this->assertEquals('flatrate', $methods[0]->getMethodCode()); + $this->assertEquals(25, $methods[0]->getAmount()); + + } + + /** + * Estimate shipment for guest cart + * + * @param int $cartId + * @return \Magento\Quote\Api\Data\ShippingMethodInterface[] + */ + private function estimateShipping($cartId) + { + $addressFactory = $this->objectManager->get(\Magento\Quote\Api\Data\AddressInterfaceFactory::class); + /** @var \Magento\Quote\Api\Data\AddressInterface $address */ + $address = $addressFactory->create(); + $address->setCountryId('US'); + $address->setRegionId(2); + + /** @var \Magento\Quote\Api\GuestShipmentEstimationInterface $estimation */ + $estimation = $this->objectManager->get(\Magento\Quote\Api\GuestShipmentEstimationInterface::class); + return $estimation->estimateByExtendedAddress($cartId, $address); + } + + /** + * Create guest quote with products + * + * @param int $itemQty + * @return int + */ + private function prepareQuote($itemQty) + { + $cartId = $this->cartManagement->createEmptyCart(); + + /** @var \Magento\Quote\Api\Data\CartItemInterfaceFactory $cartItemFactory */ + $cartItemFactory = $this->objectManager->get(\Magento\Quote\Api\Data\CartItemInterfaceFactory::class); + + /** @var \Magento\Quote\Api\Data\CartItemInterface $cartItem */ + $cartItem = $cartItemFactory->create(); + $cartItem->setQuoteId($cartId); + $cartItem->setQty($itemQty); + $cartItem->setSku('simple'); + $cartItem->setProductType(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE); + + $this->itemRepository->save($cartItem); + + return $cartId; + } +} diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/Rule/CreatedatTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/Rule/CreatedatTest.php index 274f943103c6f..35fa278df779d 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/Rule/CreatedatTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/Rule/CreatedatTest.php @@ -1,6 +1,6 @@ ['coupon_code', ['#1', '#5']], + 'Check type COUPON' => ['coupon_code', ['#1', '#2', '#5']], 'Check type NO_COUPON' => ['', ['#2', '#5']], - 'Check type COUPON_AUTO' => ['coupon_code_auto', ['#4', '#5']], - 'Check result with auto generated coupon' => ['autogenerated_3_1', ['#3', '#5']], + 'Check type COUPON_AUTO' => ['coupon_code_auto', ['#2', '#4', '#5']], + 'Check result with auto generated coupon' => ['autogenerated_3_1', ['#2', '#3', '#5']], 'Check result with non actual previously generated coupon' => [ 'autogenerated_2_1', ['#2', '#5'], ], - 'Check result with wrong code' => ['wrong_code', ['#5']] + 'Check result with wrong code' => ['wrong_code', ['#2', '#5']] ]; } @@ -221,6 +221,39 @@ protected function setSpecificTimezone($timezone) ->save(); } + /** + * Check that it's possible to find previously created rule by attribute. + * + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @magentoDataFixture Magento/SalesRule/_files/rule_custom_product_attribute.php + */ + public function testAddAttributeInConditionFilterPositive() + { + $collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\SalesRule\Model\ResourceModel\Rule\Collection::class + ); + $collection->addAttributeInConditionFilter('attribute_for_sales_rule_1'); + $item = $collection->getFirstItem(); + $this->assertEquals('50% Off on some attribute', $item->getName()); + } + + /** + * Check that it's not possible to find previously created rule by wrong attribute. + * + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @magentoDataFixture Magento/SalesRule/_files/rule_custom_product_attribute.php + */ + public function testAddAttributeInConditionFilterNegative() + { + $collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\SalesRule\Model\ResourceModel\Rule\Collection::class + ); + $collection->addAttributeInConditionFilter('attribute_for_sales_rule_2'); + $this->assertEquals(0, $collection->count()); + } + public function tearDown() { // restore default timezone diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/RuleTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/RuleTest.php new file mode 100644 index 0000000000000..3c389be70baba --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/RuleTest.php @@ -0,0 +1,27 @@ +create( + \Magento\SalesRule\Model\ResourceModel\Rule::class + ); + $items = $resource->getActiveAttributes(); + + $this->assertEquals([['attribute_code' => 'attribute_for_sales_rule_1']], $items); + } +} diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_40_percent_off.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_40_percent_off.php index 8a870b097fd67..ca5aa1596a570 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_40_percent_off.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_40_percent_off.php @@ -1,6 +1,6 @@ create(\Magento\SalesRule\Model\RuleFactory::class); +/** @var \Magento\SalesRule\Model\Rule $salesRule */ +$salesRule = $salesRuleFactory->create(); +$row = + [ + 'name' => 'Free shipping if item price >10', + 'is_active' => 1, + 'customer_group_ids' => [\Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID], + 'coupon_type' => \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON, + 'conditions' => [ + 1 => + [ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Combine::class, + 'attribute' => null, + 'operator' => null, + 'value' => '1', + 'is_value_processed' => null, + 'aggregator' => 'all', + ] + + ], + 'actions' => [ + 1 => [ + 'type' => Magento\SalesRule\Model\Rule\Condition\Product\Combine::class, + 'attribute' => null, + 'operator' => null, + 'value' => '1', + 'is_value_processed' => null, + 'aggregator' => 'all', + 'conditions' => [ + [ + 'type' => Magento\SalesRule\Model\Rule\Condition\Product::class, + 'attribute' => 'quote_item_price', + 'operator' => '==', + 'value' => '7', + 'is_value_processed' => false, + ] + ] + ] + ], + 'is_advanced' => 1, + 'simple_action' => 'by_percent', + 'discount_amount' => 0, + 'stop_rules_processing' => 0, + 'discount_qty' => 0, + 'discount_step' => 0, + 'apply_to_shipping' => 1, + 'times_used' => 0, + 'is_rss' => 1, + 'use_auto_generation' => 0, + 'uses_per_coupon' => 0, + 'simple_free_shipping' => 1, + + 'website_ids' => [ + \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Store\Model\StoreManagerInterface::class + )->getWebsite()->getId() + ] + ]; +$salesRule->loadPost($row); +$salesRule->save(); +/** @var Magento\Framework\Registry $registry */ +$registry = $objectManager->get(\Magento\Framework\Registry::class); + +$registry->unregister('cart_rule_free_shipping'); +$registry->register('cart_rule_free_shipping', $salesRule); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping_rollback.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping_rollback.php new file mode 100644 index 0000000000000..a35e9b7ac072f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_free_shipping_rollback.php @@ -0,0 +1,14 @@ +get(\Magento\Framework\Registry::class); + +/** @var Magento\SalesRule\Model\Rule $rule */ +$rule = $registry->registry('cart_rule_free_shipping'); +if ($rule) { + $rule->delete(); +} diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php index 4ff08627ea927..3062683019b03 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php @@ -1,6 +1,6 @@ create(\Magento\Eav\Model\Entity\Type::class) + ->loadByCode('catalog_category') + ->getId(); + +$attributeData = [ + 'attribute_code' => 'attribute_for_sales_rule_1', + 'entity_type_id' => $entityTypeId, + 'backend_type' => 'varchar', + 'is_required' => 1, + 'is_user_defined' => 1, + 'is_unique' => 0, + 'is_used_for_promo_rules' => 1, +]; + +/** @var \Magento\Eav\Model\Entity\Attribute $attribute */ +$attribute = $objectManager->create(\Magento\Eav\Model\Entity\Attribute::class); +$attribute->setData($attributeData); +$attribute->save(); + +/** @var \Magento\SalesRule\Model\Rule $rule */ +$salesRule = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\SalesRule\Model\Rule::class); +$salesRule->setData( + [ + 'name' => '50% Off on some attribute', + 'is_active' => 1, + 'customer_group_ids' => [\Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID], + 'coupon_type' => \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON, + 'simple_action' => 'by_percent', + 'discount_amount' => 50, + 'discount_step' => 0, + 'stop_rules_processing' => 1, + 'website_ids' => [ + \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Store\Model\StoreManagerInterface::class + )->getWebsite()->getId() + ] + ] +); + +$salesRule->getConditions()->loadArray([ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Combine::class, + 'attribute' => null, + 'operator' => null, + 'value' => '1', + 'is_value_processed' => null, + 'aggregator' => 'all', + 'conditions' => [ + [ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Product\Found::class, + 'attribute' => null, + 'operator' => null, + 'value' => '0', + 'is_value_processed' => null, + 'aggregator' => 'all', + 'conditions' => [ + [ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Product::class, + 'attribute' => 'attribute_for_sales_rule_1', + 'operator' => '==', + 'value' => '2', + 'is_value_processed' => false, + ], + ], + ], + ], +]); + +$salesRule->save(); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php new file mode 100644 index 0000000000000..016516b781634 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_free_shipping_by_product_weight.php @@ -0,0 +1,35 @@ + 'Free shipping if item weight <= 1', + 'conditions' => [ + 1 => + [ + 'type' => \Magento\SalesRule\Model\Rule\Condition\Combine::class, + 'attribute' => null, + 'operator' => null, + 'value' => '1', + 'is_value_processed' => null, + 'aggregator' => 'all', + 'conditions' => [ + [ + 'type' => Magento\SalesRule\Model\Rule\Condition\Address::class, + 'attribute' => 'weight', + 'operator' => '<=', + 'value' => '1', + 'is_value_processed' => false, + ] + ] + ] + + ], + 'actions' => [], + ]; +$salesRule->loadPost($row); +$salesRule->save(); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_specific_date.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_specific_date.php index 2775a836de799..0013d260235b2 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_specific_date.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/rule_specific_date.php @@ -1,6 +1,6 @@ composerInformationMock = $this->getMockBuilder(ComposerInformation::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + $this->componentRegistrarMock = $this->getMockBuilder(ComponentRegistrar::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->getMock(); + + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->model = $objectManager->create( + \Magento\SampleData\Model\Dependency::class, + [ + 'composerInformation' => $this->composerInformationMock, + 'filesystem' => $objectManager->get(Filesystem::class), + 'packageFactory' => $objectManager->get(PackageFactory::class), + 'componentRegistrar' => $this->componentRegistrarMock + ] + ); + } + + public function testGetSampleDataPackages() + { + $this->composerInformationMock->expects($this->once()) + ->method('getSuggestedPackages') + ->willReturn([]); + $this->componentRegistrarMock->expects($this->once()) + ->method('getPaths') + ->with(ComponentRegistrar::MODULE) + ->willReturn([ + __DIR__ . '/../_files/Modules/FirstModule', + __DIR__ . '/../_files/Modules/SecondModule', + __DIR__ . '/../_files/Modules/ThirdModule', + __DIR__ . '/../_files/Modules/FourthModule' + ]); + + $this->assertSame( + ['magento/module-first-sample-data' => '777.7.*'], + $this->model->getSampleDataPackages() + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/FirstModule/composer.json b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/FirstModule/composer.json new file mode 100644 index 0000000000000..d3f063976ea91 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/FirstModule/composer.json @@ -0,0 +1,9 @@ +{ + "name": "magento/module-first", + "description": "N/A", + "suggest": { + "magento/module-first-sample-data": "Sample Data version:777.7.*" + }, + "type": "magento2-module", + "version": "777.7.7" +} diff --git a/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/SecondModule/composer.json b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/SecondModule/composer.json new file mode 100644 index 0000000000000..b9e027b7bb6f5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/SecondModule/composer.json @@ -0,0 +1,9 @@ +{ + "name": "magento/module-second", + "description": "N/A", + "suggest": { + "magento/module-some-module": "Some Module:888.8.*" + }, + "type": "magento2-module", + "version": "777.7.7" +} diff --git a/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/ThirdModule/composer.json b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/ThirdModule/composer.json new file mode 100644 index 0000000000000..2a0d642e8e282 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SampleData/_files/Modules/ThirdModule/composer.json @@ -0,0 +1,6 @@ +{ + "name": "magento/module-second", + "description": "N/A", + "type": "magento2-module", + "version": "777.7.7" +} diff --git a/dev/tests/integration/testsuite/Magento/Search/Model/Adminhtml/System/Config/Source/EngineTest.php b/dev/tests/integration/testsuite/Magento/Search/Model/Adminhtml/System/Config/Source/EngineTest.php index 188b99df40399..f606000e7440a 100644 --- a/dev/tests/integration/testsuite/Magento/Search/Model/Adminhtml/System/Config/Source/EngineTest.php +++ b/dev/tests/integration/testsuite/Magento/Search/Model/Adminhtml/System/Config/Source/EngineTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php b/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php index 54caacfbd3ac1..b1739072e1d75 100644 --- a/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php +++ b/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php @@ -1,6 +1,6 @@ markTestSkipped('MAGETWO-64249: Unexpected test exit on Travis CI'); $this->tester->execute( [ 'directory' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/', diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nPackCommandTest.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nPackCommandTest.php index 490dc195e2400..44af81f8192f3 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nPackCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nPackCommandTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/registration.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/registration.php index 82394a6cf812b..9f01c78dcd8c2 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/registration.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/registration.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/registration.php index c6bfc1ecac5df..ff922e206c761 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/registration.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/registration.php @@ -1,6 +1,6 @@ controller = Bootstrap::getObjectManager()->create(UrlCheck::class); + } + + /** + * @param array $requestContent + * @param bool $successUrl + * @param bool $successSecureUrl + * @return void + * @dataProvider indexActionDataProvider + */ + public function testIndexAction($requestContent, $successUrl, $successSecureUrl) + { + $requestMock = $this->getMockBuilder(Request::class) + ->getMockForAbstractClass(); + $requestMock->expects($this->once()) + ->method('getContent') + ->willReturn(json_encode($requestContent)); + + $requestProperty = new \ReflectionProperty(get_class($this->controller), 'request'); + $requestProperty->setAccessible(true); + $requestProperty->setValue($this->controller, $requestMock); + + $resultModel = new JsonModel(['successUrl' => $successUrl, 'successSecureUrl' => $successSecureUrl]); + + $this->assertEquals($resultModel, $this->controller->indexAction()); + } + + /** + * @return array + */ + public function indexActionDataProvider() + { + return [ + [ + 'requestContent' => [ + 'address' => [ + 'actual_base_url' => 'http://example.com/' + ], + 'https' => [ + 'text' => 'https://example.com/', + 'admin' => true, + 'front' => false + ], + ], + 'successUrl' => true, + 'successSecureUrl' => true + ], + [ + 'requestContent' => [ + 'address' => [ + 'actual_base_url' => 'http://example.com/folder/' + ], + 'https' => [ + 'text' => 'https://example.com/folder_name/', + 'admin' => false, + 'front' => true + ], + ], + 'successUrl' => true, + 'successSecureUrl' => true + ], + [ + 'requestContent' => [ + 'address' => [ + 'actual_base_url' => 'ftp://example.com/' + ], + 'https' => [ + 'text' => 'https://example.com_test/', + 'admin' => true, + 'front' => true + ], + ], + 'successUrl' => false, + 'successSecureUrl' => false + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php index 358786901713b..9946a6188b77d 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/FixtureModelTest.php @@ -1,6 +1,6 @@ getBootstrap() + ->getApplication() + ->getDbInstance(); + if (!$db->isDbDumpExists()) { + throw new \LogicException('DB dump does not exist.'); + } + $db->restoreFromDbDump(); + self::$_generatorWorkingDir = realpath(__DIR__ . '/../../../../../../../setup/src/Magento/Setup/Fixtures'); copy( self::$_generatorWorkingDir . '/tax_rates.csv', @@ -72,38 +80,4 @@ public static function tearDownAfterClass() ] ); } - - /** - * Apply fixture file - * - * @param string $fixtureFilename - */ - public function applyFixture($fixtureFilename) - { - require $fixtureFilename; - } - - /** - * Get object manager - * - * @return \Magento\Framework\ObjectManagerInterface - */ - public function getObjectManager() - { - if (!$this->_objectManager) { - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - } - return $this->_objectManager; - } - - /** - * Reset object manager - * - * @return \Magento\Framework\ObjectManagerInterface - */ - public function resetObjectManager() - { - $this->_objectManager = null; - return $this; - } } diff --git a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/_files/small.xml b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/_files/small.xml index e01ad434c019a..4bbf385692287 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Fixtures/_files/small.xml +++ b/dev/tests/integration/testsuite/Magento/Setup/Fixtures/_files/small.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Model/ConfigOptionsListCollectorTest.php b/dev/tests/integration/testsuite/Magento/Setup/Model/ConfigOptionsListCollectorTest.php index b9f9d62cf9506..d734302fb3781 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Model/ConfigOptionsListCollectorTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Model/ConfigOptionsListCollectorTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/code/Magento/FirstModule/view/frontend/template.phtml b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/code/Magento/FirstModule/view/frontend/template.phtml index e2d29919a6045..6cca5b553c327 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/code/Magento/FirstModule/view/frontend/template.phtml +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/code/Magento/FirstModule/view/frontend/template.phtml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module1.xml b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module1.xml index 24af38bf3d6dc..5f64a5d9621dc 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module1.xml +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module1.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module2.xml b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module2.xml index 25cfe3be5562a..95fb0f803aa9d 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module2.xml +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/module2.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/GeneratorTest.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/GeneratorTest.php index be84ba364455e..531bd77ddc600 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/GeneratorTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/GeneratorTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js index 1546566ec8bb5..4e807583deb91 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml index 6738998b770fe..c10f4cc65375a 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php index 43f5717cd42cb..c5e6d2dfdbbb6 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml index b87d187eb6ae8..23d46d09ff7ed 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/mage/file.js b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/mage/file.js index c920202f5e33a..ef6f811689be8 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/mage/file.js +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/mage/file.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/varien/file.js b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/varien/file.js index c920202f5e33a..ef6f811689be8 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/varien/file.js +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/varien/file.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/Model.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/Model.php index 7183c49ecb65c..c4a564ef4f4d3 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/Model.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/Model.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/GeneratorTest.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/GeneratorTest.php index e8e40e2881eb5..3dce1bfecd0c2 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/GeneratorTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/GeneratorTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Shipping/Block/ItemsTest.php b/dev/tests/integration/testsuite/Magento/Shipping/Block/ItemsTest.php index eeef72f7495b0..a63c2da692e0d 100644 --- a/dev/tests/integration/testsuite/Magento/Shipping/Block/ItemsTest.php +++ b/dev/tests/integration/testsuite/Magento/Shipping/Block/ItemsTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->model = $this->objectManager->get(Shipping::class); + } + + /** + * Checks shipping rates processing by address. + * @covers \Magento\Shipping\Model\Shipping::collectRatesByAddress + * @return Result + */ + public function testCollectRatesByAddress() + { + $address = $this->objectManager->create(DataObject::class, [ + 'data' => [ + 'region_id' => 'CA', + 'postcode' => '11111', + 'lastname' => 'John', + 'firstname' => 'Doe', + 'street' => 'Some street', + 'city' => 'Los Angeles', + 'email' => 'john.doe@example.com', + 'telephone' => '11111111', + 'country_id' => 'US', + 'item_qty' => 1 + ] + ]); + /** @var Shipping $result */ + $result = $this->model->collectRatesByAddress($address, 'flatrate'); + static::assertInstanceOf(Shipping::class, $result); + + return $result->getResult(); + } + + /** + * Checks shipping rate details for processed address. + * @covers \Magento\Shipping\Model\Shipping::collectRatesByAddress + * @param Result $result + * @depends testCollectRatesByAddress + * @magentoConfigFixture carriers/flatrate/active 1 + * @magentoConfigFixture carriers/flatrate/price 5.00 + */ + public function testCollectRates(Result $result) + { + $rates = $result->getAllRates(); + static::assertNotEmpty($rates); + + /** @var Method $rate */ + $rate = array_pop($rates); + + static::assertInstanceOf(Method::class, $rate); + static::assertEquals('flatrate', $rate->getData('carrier')); + static::assertEquals(5, $rate->getData('price')); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sitemap/Helper/DataTest.php b/dev/tests/integration/testsuite/Magento/Sitemap/Helper/DataTest.php index 720020c23f1cb..1bb847ef6ae98 100644 --- a/dev/tests/integration/testsuite/Magento/Sitemap/Helper/DataTest.php +++ b/dev/tests/integration/testsuite/Magento/Sitemap/Helper/DataTest.php @@ -1,6 +1,6 @@ reinitialize(); $defaultStoreCode = 'default'; $modifiedDefaultCode = 'modified_default_code'; $this->changeStoreCode($defaultStoreCode, $modifiedDefaultCode); diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/App/EmulationTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/App/EmulationTest.php index e5cc9b7fe06ae..a5580e80e1a6f 100644 --- a/dev/tests/integration/testsuite/Magento/Store/Model/App/EmulationTest.php +++ b/dev/tests/integration/testsuite/Magento/Store/Model/App/EmulationTest.php @@ -1,6 +1,6 @@ objectManager = Bootstrap::getObjectManager(); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + } + + /** + * Check that behavior of setting and getting store into StoreManager is correct + * Setting: Magento\Store\Model\StoreManagerInterface::setCurrentStore + * Getting: Magento\Store\Model\StoreManagerInterface::getStore + * + * @return void + */ + public function testDefaultStoreIdIsSetCorrectly() + { + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + $this->assertEquals(Store::DEFAULT_STORE_ID, $this->storeManager->getStore()->getId()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreResolverTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreResolverTest.php new file mode 100644 index 0000000000000..86820bfb2f688 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreResolverTest.php @@ -0,0 +1,37 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->block = $this->objectManager->get(\Magento\Directory\Block\Data::class); + } + + public function testGetStoreData() + { + $methodGetStoresData = new \ReflectionMethod(\Magento\Store\Model\StoreResolver::class, 'getStoresData'); + $methodGetStoresData->setAccessible(true); + $methodReadStoresData = new \ReflectionMethod(\Magento\Store\Model\StoreResolver::class, 'readStoresData'); + $methodReadStoresData->setAccessible(true); + + $storeResolver = $this->objectManager->get(\Magento\Store\Model\StoreResolver::class); + + $storesDataRead = $methodReadStoresData->invoke($storeResolver); + CacheCleaner::cleanAll(); + $storesData = $methodGetStoresData->invoke($storeResolver); + $storesDataCached = $methodGetStoresData->invoke($storeResolver); + $this->assertEquals($storesDataRead, $storesData); + $this->assertEquals($storesDataRead, $storesDataCached); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php index 61252dabb8c20..6e3485de95e56 100644 --- a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php +++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php @@ -1,6 +1,6 @@ get(\Magento\Store\Model\StoreManagerInterface::class)->reinitStores(); } + +//if test using this fixture relies on full text functionality it is required to explicitly perform re-indexation diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/core_fixturestore_rollback.php b/dev/tests/integration/testsuite/Magento/Store/_files/core_fixturestore_rollback.php index b4191de3cd9ce..a1f22497af4e8 100644 --- a/dev/tests/integration/testsuite/Magento/Store/_files/core_fixturestore_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Store/_files/core_fixturestore_rollback.php @@ -1,6 +1,6 @@ save(); - - /* Refresh stores memory cache */ - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Store\Model\StoreManagerInterface::class - )->reinitStores(); } + +/* Refresh stores memory cache */ +\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Store\Model\StoreManagerInterface::class +)->reinitStores(); diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/second_store_rollback.php b/dev/tests/integration/testsuite/Magento/Store/_files/second_store_rollback.php index aa1c5c8bd5e6c..23af19fa43e08 100644 --- a/dev/tests/integration/testsuite/Magento/Store/_files/second_store_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Store/_files/second_store_rollback.php @@ -1,7 +1,7 @@ get(\Magento\Config\Model\ResourceModel\Config::class); +$configResource->saveConfig( + \Magento\Directory\Model\Currency::XML_PATH_CURRENCY_DEFAULT, + 'EUR', + \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE, + $websiteId +); +$configResource->saveConfig( + \Magento\Directory\Model\Currency::XML_PATH_CURRENCY_ALLOW, + 'EUR', + \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE, + $websiteId +); +$configResource->saveConfig( + \Magento\Catalog\Helper\Data::XML_PATH_PRICE_SCOPE, + \Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE, + 'default', + 0 +); +/** @var \Magento\Framework\App\Config\ReinitableConfigInterface $reinitiableConfig */ +$reinitiableConfig = $objectManager->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class); +$reinitiableConfig->setValue( + 'catalog/price/scope', + \Magento\Store\Model\Store::PRICE_SCOPE_WEBSITE +); +$observer = $objectManager->get(\Magento\Framework\Event\Observer::class); +$objectManager->get(\Magento\Catalog\Observer\SwitchPriceAttributeScopeOnConfigChange::class) + ->execute($observer); + +/** @var \Magento\Directory\Model\ResourceModel\Currency $rate */ +$rate = $objectManager->create(\Magento\Directory\Model\ResourceModel\Currency::class); +$rate->saveRates([ + 'USD' => ['EUR' => 2], + 'EUR' => ['USD' => 0.5] +]); diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_second_currency_rollback.php b/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_second_currency_rollback.php new file mode 100644 index 0000000000000..b018972619961 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_second_currency_rollback.php @@ -0,0 +1,31 @@ +get(\Magento\Config\Model\ResourceModel\Config::class); +$configResource->deleteConfig( + \Magento\Catalog\Helper\Data::XML_PATH_PRICE_SCOPE, + 'default', + 0 +); +$website = $objectManager->create(\Magento\Store\Model\Website::class); +/** @var $website \Magento\Store\Model\Website */ +$websiteId = $website->load('test', 'code')->getId(); +if ($websiteId) { + $configResource->deleteConfig( + \Magento\Directory\Model\Currency::XML_PATH_CURRENCY_DEFAULT, + \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE, + $websiteId + ); + $configResource->deleteConfig( + \Magento\Directory\Model\Currency::XML_PATH_CURRENCY_ALLOW, + \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE, + $websiteId + ); +} + +require 'second_website_with_two_stores_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_two_stores.php b/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_two_stores.php new file mode 100644 index 0000000000000..2a3f2716b8fbe --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_two_stores.php @@ -0,0 +1,63 @@ +create(\Magento\Store\Model\Website::class); +/** @var $website \Magento\Store\Model\Website */ +if (!$website->load('test', 'code')->getId()) { + $website->setData(['code' => 'test', 'name' => 'Test Website', 'default_group_id' => '1', 'is_default' => '0']); + $website->save(); +} +$websiteId = $website->getId(); +$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); +if (!$store->load('fixture_second_store', 'code')->getId()) { + $groupId = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Store\Model\StoreManagerInterface::class + )->getWebsite()->getDefaultGroupId(); + $store->setCode( + 'fixture_second_store' + )->setWebsiteId( + $websiteId + )->setGroupId( + $groupId + )->setName( + 'Fixture Second Store' + )->setSortOrder( + 10 + )->setIsActive( + 1 + ); + $store->save(); +} + +$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); +if (!$store->load('fixture_third_store', 'code')->getId()) { + $groupId = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Store\Model\StoreManagerInterface::class + )->getWebsite()->getDefaultGroupId(); + $store->setCode( + 'fixture_third_store' + )->setWebsiteId( + $websiteId + )->setGroupId( + $groupId + )->setName( + 'Fixture Third Store' + )->setSortOrder( + 11 + )->setIsActive( + 1 + ); + $store->save(); +} +/* Refresh stores memory cache */ +\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Store\Model\StoreManagerInterface::class +)->reinitStores(); + +/* Refresh CatalogSearch index */ +/** @var \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry */ +$indexerRegistry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Framework\Indexer\IndexerRegistry::class); +$indexerRegistry->get(\Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID)->reindexAll(); diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_two_stores_rollback.php b/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_two_stores_rollback.php new file mode 100644 index 0000000000000..66e3608fd40a0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Store/_files/second_website_with_two_stores_rollback.php @@ -0,0 +1,29 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +$website = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Website::class); +/** @var $website \Magento\Store\Model\Website */ +$websiteId = $website->load('test', 'code')->getId(); +if ($websiteId) { + $website->delete(); +} +$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); +if ($store->load('fixture_second_store', 'code')->getId()) { + $store->delete(); +} + +$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class); +if ($store->load('fixture_third_store', 'code')->getId()) { + $store->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/store.php b/dev/tests/integration/testsuite/Magento/Store/_files/store.php index 9bb761f0b6a13..897c7ceb6ca18 100644 --- a/dev/tests/integration/testsuite/Magento/Store/_files/store.php +++ b/dev/tests/integration/testsuite/Magento/Store/_files/store.php @@ -1,6 +1,8 @@ save(); } +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/* Refresh stores memory cache */ +$objectManager->get('Magento\Store\Model\StoreManagerInterface')->reinitStores(); diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/website.php b/dev/tests/integration/testsuite/Magento/Store/_files/website.php index 4e1f03fcadb58..9bacc3665a6c8 100644 --- a/dev/tests/integration/testsuite/Magento/Store/_files/website.php +++ b/dev/tests/integration/testsuite/Magento/Store/_files/website.php @@ -1,6 +1,6 @@ create(\Magento\Store\Model\Website::class); $website->setData(['code' => 'test', 'name' => 'Test Website', 'default_group_id' => '1', 'is_default' => '0']); $website->save(); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/* Refresh stores memory cache */ +$objectManager->get('Magento\Store\Model\StoreManagerInterface')->reinitStores(); diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/website_rollback.php b/dev/tests/integration/testsuite/Magento/Store/_files/website_rollback.php index 9c1b8fd73863d..ee1e40b342d8e 100644 --- a/dev/tests/integration/testsuite/Magento/Store/_files/website_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Store/_files/website_rollback.php @@ -1,7 +1,7 @@ assertEquals($expected['subtotal'], $total->getSubtotal()); $this->assertEquals($expected['subtotal'] + $expected['tax_amount'], $total->getSubtotalInclTax()); + $this->assertEquals($expected['subtotal'] + $expected['tax_amount'], $address->getBaseSubtotalTotalInclTax()); $this->assertEquals($expected['discount_amount'], $total->getDiscountAmount()); $items = $address->getAllItems(); /** @var \Magento\Quote\Model\Quote\Address\Item $item */ diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php index 281a49f39aa76..f8db9a875cb47 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php @@ -1,6 +1,6 @@ templateModel = $objectManager->create(\Magento\Email\Model\Template::class); $this->templateModel->load(self::TEMPLATE_CODE, 'template_code'); - + $this->templateFactoryMock->expects($this->once()) + ->method("create") + ->willReturn($this->templateModel); $this->model = $objectManager->create( \Magento\Theme\Model\Design\Config\Validator::class, [ 'templateFactory' => $this->templateFactoryMock ] @@ -58,9 +60,9 @@ protected function setUp() */ public function testValidateHasRecursiveReference() { - $this->templateFactoryMock->expects($this->once()) - ->method("create") - ->willReturn($this->templateModel); + if (!$this->templateModel->getId()) { + $this->fail('Cannot load Template model'); + } $fieldConfig = [ 'path' => 'design/email/header_template', @@ -90,7 +92,7 @@ public function testValidateHasRecursiveReference() ->willReturn([$designElementMock]); $designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig); $designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']); - $designElementMock->expects($this->once())->method('getValue')->willReturn(1); + $designElementMock->expects($this->once())->method('getValue')->willReturn($this->templateModel->getId()); $this->model->validate($designConfigMock); } @@ -132,7 +134,7 @@ public function testValidateNoRecursiveReference() ->willReturn([$designElementMock]); $designElementMock->expects($this->any())->method('getFieldConfig')->willReturn($fieldConfig); $designElementMock->expects($this->once())->method('getPath')->willReturn($fieldConfig['path']); - $designElementMock->expects($this->once())->method('getValue')->willReturn(1); + $designElementMock->expects($this->once())->method('getValue')->willReturn($this->templateModel->getId()); $this->model->validate($designConfigMock); } diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Design/Backend/ExceptionsTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Design/Backend/ExceptionsTest.php index 1e1f9d7c45b0a..721c56da95d7e 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Design/Backend/ExceptionsTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Design/Backend/ExceptionsTest.php @@ -1,25 +1,31 @@ _model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + $this->exceptions = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Theme\Model\Design\Backend\Exceptions::class ); - $this->_model->setScope('default'); - $this->_model->setScopeId(0); - $this->_model->setPath('design/theme/ua_regexp'); + $this->exceptions->setScope('default'); + $this->exceptions->setScopeId(0); + $this->exceptions->setPath('design/theme/ua_regexp'); + $this->serializer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(Json::class); } /** @@ -33,10 +39,10 @@ public function testSaveValueIsFormedNicely() '2' => ['search' => '/Firefox/', 'value' => 'Magento/blank'], ]; - $this->_model->setValue($value); - $this->_model->save(); + $this->exceptions->setValue($value); + $this->exceptions->save(); - $processedValue = unserialize($this->_model->getValue()); + $processedValue = $this->serializer->unserialize($this->exceptions->getValue()); $this->assertEquals(count($processedValue), 2, 'Number of saved values is wrong'); $entry = $processedValue['1']; @@ -56,10 +62,10 @@ public function testSaveEmptyValueIsSkipped() '3' => ['search' => '/Firefox/', 'value' => 'Magento/blank'], ]; - $this->_model->setValue($value); - $this->_model->save(); + $this->exceptions->setValue($value); + $this->exceptions->save(); - $processedValue = unserialize($this->_model->getValue()); + $processedValue = $this->serializer->unserialize($this->exceptions->getValue()); $emptyIsSkipped = isset($processedValue['1']) && !isset($processedValue['2']) && isset($processedValue['3']); $this->assertTrue($emptyIsSkipped); } @@ -72,10 +78,10 @@ public function testSaveEmptyValueIsSkipped() */ public function testSaveException($designException, $regexp) { - $this->_model->setValue(['1' => $designException]); - $this->_model->save(); + $this->exceptions->setValue(['1' => $designException]); + $this->exceptions->save(); - $processedValue = unserialize($this->_model->getValue()); + $processedValue = $this->serializer->unserialize($this->exceptions->getValue()); $this->assertEquals($processedValue['1']['regexp'], $regexp); } @@ -105,8 +111,8 @@ public function saveExceptionDataProvider() */ public function testSaveWrongException($value) { - $this->_model->setValue($value); - $this->_model->save(); + $this->exceptions->setValue($value); + $this->exceptions->save(); } /** diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/DesignTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/DesignTest.php index 6cd9746daca33..954be6bcb9d54 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/DesignTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/DesignTest.php @@ -1,10 +1,13 @@ load( $cacheId ); - $cachedDesign = unserialize($cachedDesign); + $serializer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(SerializerInterface::class); + $cachedDesign = $serializer->unserialize($cachedDesign); $this->assertInternalType('array', $cachedDesign); $this->assertArrayHasKey('design', $cachedDesign); @@ -139,7 +143,8 @@ public function testLoadChangeCache() )->load( $cacheId ); - $cachedDesign = unserialize($cachedDesign); + + $cachedDesign = $serializer->unserialize($cachedDesign); $this->assertTrue(is_array($cachedDesign)); $this->assertEquals($cachedDesign['design'], $design->getDesign()); diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/Config/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/Config/ReaderTest.php index b21316f65c55a..c92dfd22b12a9 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/Config/ReaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/Config/ReaderTest.php @@ -2,7 +2,7 @@ /** * \Magento\Theme\Model\Layout\Config\Reader * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Theme\Model\Layout\Config; diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/ConfigTest.php index 5934cc1788256..4f8a45f5b7fba 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/ConfigTest.php @@ -2,7 +2,7 @@ /** * \Magento\Theme\Model\Layout\Config * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Theme\Model\Layout; diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts.xml index ef8511214674c..6e754d3e9fed2 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts2.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts2.xml index 13757729874bb..f95c8f8ec591b 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts2.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Layout/_files/page_layouts2.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/ResourceModel/Theme/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/ResourceModel/Theme/CollectionTest.php index c3e2cb482782c..382ceca43ba92 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/ResourceModel/Theme/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/ResourceModel/Theme/CollectionTest.php @@ -1,6 +1,6 @@ 'Test physical theme', 'area' => \Magento\Framework\App\Area::AREA_FRONTEND, 'type' => ThemeInterface::TYPE_PHYSICAL, + 'code' => 'physical', ], 'virtual' => [ 'parent_id' => null, @@ -26,6 +27,7 @@ class VirtualTest extends \PHPUnit_Framework_TestCase 'theme_title' => 'Test virtual theme', 'area' => \Magento\Framework\App\Area::AREA_FRONTEND, 'type' => ThemeInterface::TYPE_VIRTUAL, + 'code' => 'virtual', ], 'staging' => [ 'parent_id' => null, @@ -33,6 +35,7 @@ class VirtualTest extends \PHPUnit_Framework_TestCase 'theme_title' => 'Test staging theme', 'area' => \Magento\Framework\App\Area::AREA_FRONTEND, 'type' => ThemeInterface::TYPE_STAGING, + 'code' => 'staging', ], ]; diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/FileTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/FileTest.php index f4eb5566ea0a7..bc3cc14ec8175 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/FileTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/FileTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/b_e/theme.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/b_e/theme.xml index 71d98d1885bde..9a75a966a7dcc 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/b_e/theme.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/b_e/theme.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_default/theme.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_default/theme.xml index 38cb424c503b0..9955934a51894 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_default/theme.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_default/theme.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_g/theme.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_g/theme.xml index 3f9dc3d19bf54..a30e5e9502a66 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_g/theme.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/Source/_files/design/frontend/magento_g/theme.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/ThemeProviderTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/ThemeProviderTest.php new file mode 100644 index 0000000000000..1e92c0eb27290 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/ThemeProviderTest.php @@ -0,0 +1,70 @@ +themeProviderOne = $objectManager->create(ThemeProvider::class); + $this->themeProviderTwo = clone $this->themeProviderOne; + $this->themeCollection = $objectManager->create(ThemeCollection::class); + CacheCleaner::clean(); + } + + public function testGetThemeById() + { + /** @var Theme $theme */ + foreach ($this->themeCollection as $theme) { + $theme = $this->themeProviderOne->getThemeById($theme->getId()); + $this->assertSame( + $theme, + $this->themeProviderOne->getThemeById($theme->getId()) + ); + $this->assertSame( + $theme->getData(), + $this->themeProviderTwo->getThemeById($theme->getId())->getData() + ); + } + } + + public function testGetThemeByFullPath() + { + /** @var Theme $theme */ + foreach ($this->themeCollection as $theme) { + $theme = $this->themeProviderOne->getThemeByFullPath($theme->getFullPath()); + $this->assertSame( + $theme, + $this->themeProviderOne->getThemeByFullPath($theme->getFullPath()) + ); + $this->assertSame( + $theme->getData(), + $this->themeProviderTwo->getThemeByFullPath($theme->getFullPath())->getData() + ); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/ThemeTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/ThemeTest.php index db7b9ff35d092..180f072db55b4 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/ThemeTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/ThemeTest.php @@ -1,6 +1,6 @@ assertEquals(\Magento\Framework\View\DesignInterface::DEFAULT_AREA, $this->_model->getArea()); \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\App\State::class) - ->setAreaCode('test'); - $this->assertEquals('test', $this->_model->getArea()); + ->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML); + $this->assertEquals(\Magento\Framework\App\Area::AREA_ADMINHTML, $this->_model->getArea()); } public function testSetDesignTheme() diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/adminhtml/Vendor/test/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/adminhtml/Vendor/test/registration.php index c4fd545437d84..e9d76a19f9457 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/adminhtml/Vendor/test/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/adminhtml/Vendor/test/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/area_two/Vendor/theme_one/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/area_two/Vendor/theme_one/registration.php index f52e9a4aaa6d3..b5a380ce79012 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/area_two/Vendor/theme_one/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/area_two/Vendor/theme_one/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/design_area/Vendor/theme_one/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/design_area/Vendor/theme_one/registration.php index d7bca06c69c44..8b2aa4df7905b 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/design_area/Vendor/theme_one/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/design_area/Vendor/theme_one/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default/registration.php index f2aa03ea41894..a72f652ffd4ef 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default_iphone/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default_iphone/registration.php index 8015b1e81df12..94c0db0bfeef2 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default_iphone/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Magento/default_iphone/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/cache_test_theme/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/cache_test_theme/registration.php index a5d2446477272..25637e16fd4d3 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/cache_test_theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/cache_test_theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view_type_default.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view_type_default.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view_type_default.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_category_view_type_default.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view_type_simple.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view_type_simple.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view_type_simple.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/catalog_product_view_type_simple.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/templates/theme_template.phtml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/templates/theme_template.phtml index 2a0cd37c68d37..1e805048885be 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/templates/theme_template.phtml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Catalog/templates/theme_template.phtml @@ -1,5 +1,5 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml index 49891bcdaeedd..a44ce7b861622 100755 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_main.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_sample.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_sample.xml index b520dcdab4f31..15c1c3b2c02b9 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_sample.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/Magento_Core/layout_test_handle_sample.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/etc/view.xml b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/etc/view.xml index 386519bf34e07..4a6a58f276ae7 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/etc/view.xml +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/etc/view.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/registration.php index 1bec4b70aa140..f8c6b9088c42c 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/css/styles.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/css/styles.css index ef062ee1606c7..14875d41267fc 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/css/styles.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/css/styles.css @@ -1,4 +1,4 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/js/tabs.js b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/js/tabs.js index ef062ee1606c7..14875d41267fc 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/js/tabs.js +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/js/tabs.js @@ -1,4 +1,4 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source.css index 1b37adace875c..cbeb427496de4 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source.css @@ -1,6 +1,6 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -#header{color: #4d926f}h2{color: #4d926f}#header{-webkit-border-radius: 5px;-moz-border-radius: 5px;-ms-border-radius: 5px;-o-border-radius: 5px;border-radius: 5px}#footer{-webkit-border-radius: 10px;-moz-border-radius: 10px;-ms-border-radius: 10px;-o-border-radius: 10px;border-radius: 10px}#header h1{font-size: 26px;font-weight: bold}#header p{font-size: 12px}#header p a{text-decoration: none}#header p a:hover{border-width: 1px}#header{color: #333;border-left: 1px;border-right: 2px}#footer{color: #141;border-color: #7d2717} \ No newline at end of file +#header{color: #4d926f}h2{color: #4d926f}#header{-webkit-border-radius: 5px;-moz-border-radius: 5px;-ms-border-radius: 5px;-o-border-radius: 5px;border-radius: 5px}#footer{-webkit-border-radius: 10px;-moz-border-radius: 10px;-ms-border-radius: 10px;-o-border-radius: 10px;border-radius: 10px}#header h1{font-size: 26px;font-weight: bold}#header p{font-size: 12px}#header p a{text-decoration: none}#header p a:hover{border-width: 1px}#header{color: #333;border-left: 1px;border-right: 2px}#footer{color: #141;border-color: #7d2717} diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source_dev.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source_dev.css index b904af3d2ed88..2154504cec330 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source_dev.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/result_source_dev.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/source.less b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/source.less index 0b32dd22ed44d..c4f36c0fc6b08 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/source.less +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/default/web/source.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/publication/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/publication/registration.php index 59bb5300266c4..390352348f718 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/publication/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/publication/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/test_theme/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/test_theme/registration.php index 22443a56f89e8..c4b21e01387c8 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/test_theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Test/test_theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/Fixture_Module/web/fixture_script.js b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/Fixture_Module/web/fixture_script.js index 62d637e4bcbd1..96ec94baf0b66 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/Fixture_Module/web/fixture_script.js +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/Fixture_Module/web/fixture_script.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* modular fixture view file located inside the nested view of the custom theme */ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/registration.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/registration.php index 2c55511dce842..c95287f301526 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/registration.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/custom_theme/registration.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/access_violation.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/access_violation.php index 2a0cd37c68d37..1e805048885be 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/access_violation.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/access_violation.php @@ -1,5 +1,5 @@ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/base64.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/base64.css index 64a7570514936..c3315936d7a99 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/base64.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/base64.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/deep/recursive.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/deep/recursive.css index 263de01d6ff4d..451754b8885dc 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/deep/recursive.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/deep/recursive.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ dt {background: url('../../recursive2.gif')} diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/exception.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/exception.css index 8d37dfa8619a9..7b4bb40b1a174 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/exception.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/exception.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ li.rogue {background: url(../access_violation.php);} diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/file.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/file.css index 4ace7c612b14a..158899c88756b 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/file.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/css/file.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @import url(../recursive.css); diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/recursive.css b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/recursive.css index 75def6dc64189..3d96d38aadc62 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/recursive.css +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/recursive.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ dl {background: url(recursive.gif)} diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/scripts.js b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/scripts.js index eacb5d8480be1..b03df81f45265 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/scripts.js +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/Vendor/default/web/scripts.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /* scripts.js */ diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/access_violation.php b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/access_violation.php index 2a0cd37c68d37..1e805048885be 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/access_violation.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/_files/design/frontend/access_violation.php @@ -1,5 +1,5 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/custom/prohibited.filename.xml b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/custom/prohibited.filename.xml index 900768551688b..240fc70a32fe1 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/custom/prohibited.filename.xml +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/custom/prohibited.filename.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/local.xml b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/local.xml index 7fc4daf68b02e..7ffc557503a99 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/local.xml +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/local.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/z.xml b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/z.xml index 3cb8c9fa81ab5..0f51b97b5e788 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/z.xml +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/local_config/z.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/a.xml b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/a.xml index a23a310485714..55f931eefd82c 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/a.xml +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/a.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/b.xml b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/b.xml index 531c4db43c7a2..b77a5d94a748b 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/b.xml +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/b.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/custom/local.xml b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/custom/local.xml index 544cce826f159..a0d9dc2781d6f 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/custom/local.xml +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/local_config/no_local_config/custom/local.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/locale/en_AU/config.xml b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/locale/en_AU/config.xml index 191748f129605..40c1fd4c3c92d 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/_files/locale/en_AU/config.xml +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/_files/locale/en_AU/config.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Translation/_files/db_translate.php b/dev/tests/integration/testsuite/Magento/Translation/_files/db_translate.php index 9294096713696..cfa47fb376997 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/_files/db_translate.php +++ b/dev/tests/integration/testsuite/Magento/Translation/_files/db_translate.php @@ -1,6 +1,6 @@ create(\Magento\User\Model\User::class); + /** @var \Magento\Framework\Message\ManagerInterface $messageManager */ + $messageManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\Message\ManagerInterface::class); + $user->load(1); + $this->getRequest()->setPostValue('user_id', $user->getId() . '_suffix_ignored_in_mysql_casting_to_int'); + + $this->dispatch('backend/admin/user/delete'); + $message = $messageManager->getMessages()->getLastAddedMessage()->getText(); + $this->assertEquals('You cannot delete your own account.', $message); + } +} diff --git a/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php b/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php index b705228785ee6..dd79f27ec28bc 100644 --- a/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php +++ b/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php @@ -1,6 +1,6 @@ get( - \Magento\Backend\App\ConfigInterface::class + \Magento\Framework\App\Config\MutableScopeConfigInterface::class ); $this->assertEquals( 2, diff --git a/dev/tests/integration/testsuite/Magento/User/Model/ResourceModel/Role/User/CollectionTest.php b/dev/tests/integration/testsuite/Magento/User/Model/ResourceModel/Role/User/CollectionTest.php index ce5010064bfd8..66a2d0e69cd78 100644 --- a/dev/tests/integration/testsuite/Magento/User/Model/ResourceModel/Role/User/CollectionTest.php +++ b/dev/tests/integration/testsuite/Magento/User/Model/ResourceModel/Role/User/CollectionTest.php @@ -1,6 +1,6 @@ _model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\User\Model\User::class + \Magento\User\Model\User::class ); $this->_dateTime = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Framework\Stdlib\DateTime::class @@ -125,7 +125,7 @@ public function testGetRoles() $this->_model->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); $roles = $this->_model->getRoles(); $this->assertEquals(1, count($roles)); - $this->assertEquals(1, $roles[0]); + $this->assertEquals(\Magento\TestFramework\Bootstrap::ADMIN_ROLE_NAME, $this->_model->getRole()->getRoleName()); $this->_model->setRoleId(self::$_newRole->getId())->save(); $roles = $this->_model->getRoles(); $this->assertEquals(1, count($roles)); @@ -140,7 +140,7 @@ public function testGetRole() $this->_model->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); $role = $this->_model->getRole(); $this->assertInstanceOf(\Magento\Authorization\Model\Role::class, $role); - $this->assertEquals(1, $role->getId()); + $this->assertEquals(\Magento\TestFramework\Bootstrap::ADMIN_ROLE_NAME, $this->_model->getRole()->getRoleName()); $this->_model->setRoleId(self::$_newRole->getId())->save(); $role = $this->_model->getRole(); $this->assertEquals(self::$_newRole->getId(), $role->getId()); @@ -152,7 +152,8 @@ public function testGetRole() public function testDeleteFromRole() { $this->_model->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); - $this->_model->setRoleId(1)->deleteFromRole(); + $roles = $this->_model->getRoles(); + $this->_model->setRoleId(reset($roles))->deleteFromRole(); $role = $this->_model->getRole(); $this->assertNull($role->getId()); } @@ -160,9 +161,10 @@ public function testDeleteFromRole() public function testRoleUserExists() { $this->_model->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); - $this->_model->setRoleId(1); + $role = $this->_model->getRole(); + $this->_model->setRoleId($role->getId()); $this->assertTrue($this->_model->roleUserExists()); - $this->_model->setRoleId(2); + $this->_model->setRoleId(100); $this->assertFalse($this->_model->roleUserExists()); } @@ -239,8 +241,9 @@ public function testAuthenticateInactiveUser() */ public function testAuthenticateUserWithoutRole() { - $this->_model->load(1); - $this->_model->setRoleId(1)->deleteFromRole(); + $this->_model->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); + $roles = $this->_model->getRoles(); + $this->_model->setRoleId(reset($roles))->deleteFromRole(); $this->_model->authenticate( \Magento\TestFramework\Bootstrap::ADMIN_NAME, \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD @@ -293,7 +296,8 @@ public function testHasAssigned2Role() $role = $this->_model->hasAssigned2Role($this->_model); $this->assertEquals(1, count($role)); $this->assertArrayHasKey('role_id', $role[0]); - $this->_model->setRoleId(1)->deleteFromRole(); + $roles = $this->_model->getRoles(); + $this->_model->setRoleId(reset($roles))->deleteFromRole(); $this->assertEmpty($this->_model->hasAssigned2Role($this->_model)); } diff --git a/dev/tests/integration/testsuite/Magento/User/_files/dummy_user.php b/dev/tests/integration/testsuite/Magento/User/_files/dummy_user.php index 6ddc19e9aef0e..51e9bc73b8f63 100644 --- a/dev/tests/integration/testsuite/Magento/User/_files/dummy_user.php +++ b/dev/tests/integration/testsuite/Magento/User/_files/dummy_user.php @@ -1,6 +1,6 @@ _model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Variable\Model\Variable\Config::class ); } @@ -28,8 +28,9 @@ protected function setUp() public function testGetWysiwygJsPluginSrc() { $src = $this->_model->getWysiwygJsPluginSrc(); - $this->assertStringStartsWith('http://localhost/pub/static/adminhtml/Magento/backend/en_US/mage/adminhtml/', - $src); - $this->assertStringEndsWith('editor_plugin.js', $src); + $this->assertStringMatchesFormat( + 'http://localhost/pub/static/%s/adminhtml/Magento/backend/en_US/mage/adminhtml/%s/editor_plugin.js', + $src + ); } } diff --git a/dev/tests/integration/testsuite/Magento/Variable/Model/VariableTest.php b/dev/tests/integration/testsuite/Magento/Variable/Model/VariableTest.php index 4895bff629093..1b1c5738e80f1 100644 --- a/dev/tests/integration/testsuite/Magento/Variable/Model/VariableTest.php +++ b/dev/tests/integration/testsuite/Magento/Variable/Model/VariableTest.php @@ -1,6 +1,6 @@ repository = $objectManager->create(PaymentTokenRepository::class); - $this->searchCriteriaBuilder = $objectManager->create( - \Magento\Framework\Api\SearchCriteriaBuilder::class - ); - $this->filterBuilder = $objectManager->get( - \Magento\Framework\Api\FilterBuilder::class - ); - $this->sortOrderBuilder = $objectManager->get( - \Magento\Framework\Api\SortOrderBuilder::class - ); + $this->objectManager = Bootstrap::getObjectManager(); + $this->repository = $this->objectManager->create(PaymentTokenRepository::class); + $this->searchCriteriaBuilder = $this->objectManager->create(SearchCriteriaBuilder::class); + $this->filterBuilder = $this->objectManager->get(FilterBuilder::class); + $this->sortOrderBuilder = $this->objectManager->get(SortOrderBuilder::class); } /** @@ -77,4 +86,26 @@ public function testGetListWithMultipleFiltersAndSorting() $this->assertEquals('second', array_shift($items)->getPaymentMethodCode()); $this->assertEquals('first', array_shift($items)->getPaymentMethodCode()); } + + /** + * @covers \Magento\Vault\Model\PaymentTokenRepository::delete + * @magentoDataFixture Magento/Vault/_files/token.php + */ + public function testDelete() + { + /** @var PaymentTokenManagement $tokenManagement */ + $tokenManagement = $this->objectManager->get(PaymentTokenManagement::class); + + $token = $tokenManagement->getByPublicHash('public_hash', 0); + + /** @var PaymentTokenRepository $tokenRepository */ + $tokenRepository = $this->objectManager->get(PaymentTokenRepository::class); + $tokenRepository->delete($token); + + $deletedToken = $tokenRepository->getById($token->getEntityId()); + + static::assertEquals('public_hash', $deletedToken->getPublicHash()); + static::assertFalse($deletedToken->getIsActive()); + static::assertFalse($deletedToken->getIsVisible()); + } } diff --git a/dev/tests/integration/testsuite/Magento/Vault/Model/ResourceModel/PaymentTokenTest.php b/dev/tests/integration/testsuite/Magento/Vault/Model/ResourceModel/PaymentTokenTest.php index 88974f0d9cc5e..530abe2c023b8 100644 --- a/dev/tests/integration/testsuite/Magento/Vault/Model/ResourceModel/PaymentTokenTest.php +++ b/dev/tests/integration/testsuite/Magento/Vault/Model/ResourceModel/PaymentTokenTest.php @@ -1,6 +1,6 @@ create(PaymentToken::class); + +$token->setGatewayToken('gateway_token') + ->setPublicHash('public_hash') + ->setPaymentMethodCode('vault_payment') + ->setType('card') + ->setExpiresAt(strtotime('+1 year')) + ->setIsVisible(true) + ->setIsActive(true); + +/** @var PaymentTokenRepository $tokenRepository */ +$tokenRepository = $objectManager->create(PaymentTokenRepository::class); +$tokenRepository->save($token); diff --git a/dev/tests/integration/testsuite/Magento/Version/Controller/Index/IndexTest.php b/dev/tests/integration/testsuite/Magento/Version/Controller/Index/IndexTest.php index f230d9bc33ba4..66c82da6aeb36 100644 --- a/dev/tests/integration/testsuite/Magento/Version/Controller/Index/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Version/Controller/Index/IndexTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapiB.xml b/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapiB.xml index 273164f02e0a2..3b0cc9bad6ab4 100644 --- a/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapiB.xml +++ b/dev/tests/integration/testsuite/Magento/Webapi/Model/Config/_files/webapiB.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Webapi/Model/ServiceMetadataTest.php b/dev/tests/integration/testsuite/Magento/Webapi/Model/ServiceMetadataTest.php new file mode 100644 index 0000000000000..4cfc77c501578 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Webapi/Model/ServiceMetadataTest.php @@ -0,0 +1,135 @@ +serviceMetadata = $objectManager->create(ServiceMetadata::class); + } + + public function testGetServiceMetadata() + { + $expected = [ + 'methods' => [ + 'activate' => [ + 'method' => 'activate', + 'inputRequired' => false, + 'isSecure' => false, + 'resources' => [ + 'Magento_Customer::manage' + ], + 'documentation' => 'Activate a customer account using a key that was sent in a confirmation email.', + 'interface' => [ + 'in' => [ + 'parameters' => [ + 'email' => [ + 'type' => 'string', + 'required' => true, + 'documentation' => null + ], + 'confirmationKey' => [ + 'type' => 'string', + 'required' => true, + 'documentation' => null + ] + ] + ], + 'out' => [ + 'parameters' => [ + 'result' => [ + 'type' => 'CustomerDataCustomerInterface', + 'required' => true, + 'documentation' => '' + ] + ], + 'throws' => [ + '\\' . LocalizedException::class + ] + ] + ] + ] + ], + 'class' => AccountManagementInterface::class, + 'description' => 'Interface for managing customers accounts.', + ]; + $actual = $this->serviceMetadata->getServiceMetadata('customerAccountManagementV1'); + $this->assertEquals(array_replace_recursive($actual, $expected), $actual); + } + + public function testGetRouteMetadata() + { + $expected = [ + 'methods' => [ + 'activate' => [ + 'method' => 'activate', + 'inputRequired' => false, + 'isSecure' => false, + 'resources' => [ + 'Magento_Customer::manage' + ], + 'documentation' => 'Activate a customer account using a key that was sent in a confirmation email.', + 'interface' => [ + 'in' => [ + 'parameters' => [ + 'email' => [ + 'type' => 'string', + 'required' => true, + 'documentation' => null + ], + 'confirmationKey' => [ + 'type' => 'string', + 'required' => true, + 'documentation' => null + ] + ] + ], + 'out' => [ + 'parameters' => [ + 'result' => [ + 'type' => 'CustomerDataCustomerInterface', + 'required' => true, + 'documentation' => '' + ] + ], + 'throws' => [ + '\\' . LocalizedException::class + ] + ] + ] + ] + ], + 'class' => AccountManagementInterface::class, + 'description' => 'Interface for managing customers accounts.', + 'routes' => [ + '/V1/customers/me/activate' => [ + 'PUT' => [ + 'method' => 'activateById', + 'parameters' => [ + 'customerId' => [ + 'force' => true, + 'value' => '%customer_id%' + ] + ] + ] + ] + ] + ]; + $actual = $this->serviceMetadata->getRouteMetadata('customerAccountManagementV1'); + $this->assertEquals(array_replace_recursive($actual, $expected), $actual); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Webapi/Model/Soap/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Webapi/Model/Soap/ConfigTest.php new file mode 100644 index 0000000000000..73bc53cd8b85a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Webapi/Model/Soap/ConfigTest.php @@ -0,0 +1,115 @@ +soapConfig = $objectManager->create(Config::class); + } + + public function testGetRequestedSoapServices() + { + $expected = [ + 'customerAccountManagementV1' => [ + 'methods' => [ + 'activate' => [ + 'method' => 'activate', + 'inputRequired' => false, + 'isSecure' => false, + 'resources' => [ + 'Magento_Customer::manage' + ], + 'documentation' + => 'Activate a customer account using a key that was sent in a confirmation email.', + 'interface' => [ + 'in' => [ + 'parameters' => [ + 'email' => [ + 'type' => 'string', + 'required' => true, + 'documentation' => null + ], + 'confirmationKey' => [ + 'type' => 'string', + 'required' => true, + 'documentation' => null + ] + ] + ], + 'out' => [ + 'parameters' => [ + 'result' => [ + 'type' => 'CustomerDataCustomerInterface', + 'required' => true, + 'documentation' => null + ] + ], + 'throws' => [ + '\\' . LocalizedException::class + ] + ] + ] + ] + ], + 'class' => AccountManagementInterface::class, + 'description' => 'Interface for managing customers accounts.', + ] + ]; + $actual = $this->soapConfig->getRequestedSoapServices( + [ + 'customerAccountManagementV1', + 'NonExistentService' + ] + ); + $this->assertEquals(array_replace_recursive($actual, $expected), $actual); + } + + public function testGetServiceMethodInfo() + { + $expected = [ + 'class' => CustomerRepositoryInterface::class, + 'method' => 'getById', + 'isSecure' => false, + 'resources' => [ + 'Magento_Customer::customer', + 'self' + ], + ]; + $actual = $this->soapConfig->getServiceMethodInfo( + 'customerCustomerRepositoryV1GetById', + [ + 'customerCustomerRepositoryV1', + 'NonExistentService' + ] + ); + $this->assertEquals($expected, $actual); + } + + public function testGetSoapOperation() + { + $expected = 'customerAccountManagementV1Activate'; + $actual = $this->soapConfig + ->getSoapOperation( + AccountManagementInterface::class, + 'activate', + 'V1' + ); + $this->assertEquals($expected, $actual); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Webapi/Service/Entity/TestService.php b/dev/tests/integration/testsuite/Magento/Webapi/Service/Entity/TestService.php index 121edfe87973e..ef0fd6ecc9322 100644 --- a/dev/tests/integration/testsuite/Magento/Webapi/Service/Entity/TestService.php +++ b/dev/tests/integration/testsuite/Magento/Webapi/Service/Entity/TestService.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_containers.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_imported_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_imported_containers.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_imported_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_inherited_imported_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_own_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_own_containers.xml index 8d8ac056ff5f0..a527893a484c1 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_own_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_with_own_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_without_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_without_containers.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_without_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/child_page_without_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/customer_account.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/customer_account.xml index 7ce58ea03467c..7797a58139ca2 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/customer_account.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/customer_account.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/non_page_handle_with_own_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/non_page_handle_with_own_containers.xml index 73394472fd10e..8777d4902e889 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/non_page_handle_with_own_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/non_page_handle_with_own_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/page_empty.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/page_empty.xml index 21a089ed8ca83..8afcb65711cd2 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/page_empty.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/page_empty.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_imported_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_imported_containers.xml index ea8149386f46d..710cad45a35c9 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_imported_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_imported_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_own_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_own_containers.xml index 7bdbc63b324de..9f3e2677e6fc0 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_own_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_with_own_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_containers.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_own_containers.xml b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_own_containers.xml index 8bdcff2f3e49d..a96006a8c4a0a 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_own_containers.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/layout/root_page_without_own_containers.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/page_types_select.html b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/page_types_select.html index 20f994e04ac1b..9d0301203d11f 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/page_types_select.html +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Chooser/_files/page_types_select.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/LayoutTest.php b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/LayoutTest.php index 67b19c7cee51a..813dda78207fa 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/LayoutTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/LayoutTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/expectedGlobalArray.php b/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/expectedGlobalArray.php index e96b83bd84657..bb047badee871 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/expectedGlobalArray.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/expectedGlobalArray.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/orders_and_returns_customized.xml b/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/orders_and_returns_customized.xml index d59af5aea2c55..05118fa3e8a14 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/orders_and_returns_customized.xml +++ b/dev/tests/integration/testsuite/Magento/Widget/Model/Config/_files/orders_and_returns_customized.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/Layout/UpdateTest.php b/dev/tests/integration/testsuite/Magento/Widget/Model/Layout/UpdateTest.php index 1f815af5642ab..d371e829d6f81 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Model/Layout/UpdateTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Model/Layout/UpdateTest.php @@ -1,6 +1,6 @@ assertArrayHasKey('widget_window_url', $settings); $jsFilename = $settings['widget_plugin_src']; - $this->assertStringStartsWith('http://localhost/pub/static/adminhtml/Magento/backend/en_US/', $jsFilename); - $this->assertStringEndsWith('editor_plugin.js', $jsFilename); + $this->assertStringMatchesFormat( + 'http://localhost/pub/static/%s/adminhtml/Magento/backend/en_US/%s/editor_plugin.js', + $jsFilename + ); $this->assertInternalType('array', $settings['widget_placeholders']); diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php b/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php index c616eb0e525ca..8df7495601955 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php @@ -1,6 +1,6 @@ assertContains('types', $result); $this->assertContains('type_1,type_2', $result); $this->assertContains('conditions_encoded', $result); - $this->assertContains('s:50:`Magento|CatalogWidget|Model|Rule|Condition|Combine`', $result); - $this->assertContains('s:50:`Magento|CatalogWidget|Model|Rule|Condition|Product`', $result); + $this->assertContains('`Magento|CatalogWidget|Model|Rule|Condition|Combine`', $result); + $this->assertContains('`Magento|CatalogWidget|Model|Rule|Condition|Product`', $result); + } + + /** + * @covers \Magento\Widget\Model\Widget\Instance::beforeSave() + * @magentoDataFixture Magento/Widget/_files/new_widget.php + * @dataProvider beforeSaveDataProvider + * @param array $expected + */ + public function testBeforeSave(array $expected) + { + /** @var \Magento\Widget\Model\ResourceModel\Widget\Instance $resourceModel */ + $resourceModel = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Widget\Model\ResourceModel\Widget\Instance::class); + $resourceModel->load($this->_model, 'Magento\Widget\NewSampleWidget', 'instance_type'); + + $this->assertSame($expected, $this->_model->getWidgetParameters()); + } + + /** + * @return array + */ + public function beforeSaveDataProvider() + { + return [ + # Variation 1 + [ + ['block_id' => '2'] + ] + ]; } } diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php b/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php index 8bbf147c4b05b..7dd26b5e2d4bd 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/integration/testsuite/Magento/Widget/_files/layout_cache.php b/dev/tests/integration/testsuite/Magento/Widget/_files/layout_cache.php index e8331f393fa56..930254718fc90 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/_files/layout_cache.php +++ b/dev/tests/integration/testsuite/Magento/Widget/_files/layout_cache.php @@ -1,6 +1,6 @@ get(\Magento\Widget\Model\ResourceModel\Widget\Instance::class); + +$model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Widget\Model\Widget\Instance::class); + +// Set default theme as work ground for MAGETWO-63643 +/** @var \Magento\Framework\View\Design\ThemeInterface $theme */ +$theme = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Framework\View\Design\ThemeInterface::class +); +$theme->load('Magento/luma', 'theme_path'); + +$model->setData( + [ + 'instance_type' => 'Magento\\Widget\\NewSampleWidget', + 'theme_id' => $theme->getId(), + 'title' => 'New Sample widget title', + 'store_ids' => [ + 0 => '0', + ], + 'widget_parameters' => [ + 'block_id' => '2', + ], + 'sort_order' => '0', + 'page_groups' => [], + 'instance_code' => 'new_sample_widget', + ] +); + +$resourceModel->save($model); diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php index 89c0cf575bc10..8e6ebb2a46db1 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Block/Customer/Wishlist/Item/ColumnTest.php @@ -1,6 +1,6 @@ objectManager = \Magento\Framework\App\ObjectManager::getInstance(); + $this->model = $this->objectManager->get(\Magento\Wishlist\Model\Item::class); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ + public function testBuyRequest() + { + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $product = $productRepository->getById(1); + + /** @var \Magento\Wishlist\Model\Item\Option $option */ + $option = $this->objectManager->create( + \Magento\Wishlist\Model\Item\Option::class, + ['data' => ['code' => 'info_buyRequest', 'value' => '{"qty":23}']] + ); + $option->setProduct($product); + $this->model->addOption($option); + + // Assert getBuyRequest method + $buyRequest = $this->model->getBuyRequest(); + $this->assertEquals($buyRequest->getOriginalQty(), 23); + + // Assert mergeBuyRequest method + $this->model->mergeBuyRequest(['qty' => 11, 'additional_data' => 'some value']); + $buyRequest = $this->model->getBuyRequest(); + $this->assertEquals( + ['additional_data' => 'some value', 'qty' => 0, 'original_qty' => 11], + $buyRequest->getData() + ); + } + + public function testSetBuyRequest() + { + $buyRequest = $this->objectManager->create( + \Magento\Framework\DataObject::class, + ['data' => ['field_1' => 'some data', 'field_2' => 234]] + ); + + $this->model->setBuyRequest($buyRequest); + + $this->assertEquals( + '{"field_1":"some data","field_2":234,"id":null}', + $this->model->getData('buy_request') + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Model/ResourceModel/Item/CollectionTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Model/ResourceModel/Item/CollectionTest.php new file mode 100644 index 0000000000000..91184919ef278 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Model/ResourceModel/Item/CollectionTest.php @@ -0,0 +1,74 @@ +objectManager = ObjectManager::getInstance(); + $this->wishlist = $this->objectManager->create(Wishlist::class); + $this->itemCollection = $this->objectManager->get(Collection::class); + $this->attributeConfig = $this->objectManager->get(Config\Data::class); + } + + /** + * Verify that Wishlist Item Collection uses Catalog Attributes defined in the configuration. + * + * @magentoDataFixture Magento/Wishlist/_files/wishlist_shared.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + */ + public function testLoadedProductAttributes() + { + $this->addAttributesToWishlistConfig([ + 'short_description', + ]); + $this->wishlist->loadByCode('fixture_unique_code'); + $this->itemCollection->addWishlistFilter($this->wishlist); + + /** @var Product $productOnWishlist */ + $productOnWishlist = $this->itemCollection->getFirstItem()->getProduct(); + $this->assertEquals('Simple Product', $productOnWishlist->getName()); + $this->assertEquals('Short description', $productOnWishlist->getData('short_description')); + } + + /** + * @param array $attributes + */ + private function addAttributesToWishlistConfig($attributes) + { + $this->attributeConfig->merge([ + 'wishlist_item' => $attributes + ]); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist.php b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist.php index 0022455d9945f..be3b53b050d6b 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/_files/wishlist.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/js/JsTestDriver/testsuite/lib/storage/index.html b/dev/tests/js/JsTestDriver/testsuite/lib/storage/index.html index 41abf67fff6b0..35e8f9192c92a 100644 --- a/dev/tests/js/JsTestDriver/testsuite/lib/storage/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/lib/storage/index.html @@ -2,7 +2,7 @@ /** * @category storage * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/js/JsTestDriver/testsuite/lib/storage/test-storage.js b/dev/tests/js/JsTestDriver/testsuite/lib/storage/test-storage.js index cccc84980ca1e..9ee9e3a24aeaa 100644 --- a/dev/tests/js/JsTestDriver/testsuite/lib/storage/test-storage.js +++ b/dev/tests/js/JsTestDriver/testsuite/lib/storage/test-storage.js @@ -1,7 +1,7 @@ /** * @category mage.collapsible * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -20,4 +20,4 @@ test('Storage', function() { equal($.cookie(key),"true"); equal($.cookie(key),storage.get(key)); } -}); \ No newline at end of file +}); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/_demo/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/_demo/index.html index 3cf3e59bff476..e13536e3d2893 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/_demo/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/_demo/index.html @@ -2,7 +2,7 @@ /** * @category mage._demo * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -21,4 +21,4 @@
    - \ No newline at end of file + diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/_demo/test.js b/dev/tests/js/JsTestDriver/testsuite/mage/_demo/test.js index e71e4e43d8425..e87f82bdab631 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/_demo/test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/_demo/test.js @@ -1,7 +1,7 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ TestCase( "hello test", function() { ok( 1 == "1", "Passed!" ); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js index 20c87b2c3ff64..544204d31cab2 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js @@ -1,7 +1,7 @@ /** * @category mage.js * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html index af98ecc833e2d..9b326a756059a 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html @@ -2,7 +2,7 @@ /** * @category mage.accordion * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -28,4 +28,4 @@
    - \ No newline at end of file + diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/button/button-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/button/button-test.js index 85990213c089b..7ea10f09cb621 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/button/button-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/button/button-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ ButtonTest = TestCase('ButtonTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-qunit.js b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-qunit.js index 344600d3fddee..2f2d2e4254434 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-qunit.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-qunit.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -74,4 +74,4 @@ test( "destroy", function() { calendarExist = calendar.is(':mage-calendar'); calendar.calendar('destroy'); equal(true, calendarExist != calendar.is(':mage-calendar')); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-test.js index c7b704c062efc..65f1f4b06f645 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ CalendarTest = TestCase('CalendarTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar.html b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar.html index db26e2f1bbbd6..46d931ac9e61f 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/calendar.html @@ -2,7 +2,7 @@ /** * @category mage.calendar * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -28,4 +28,4 @@
    - \ No newline at end of file + diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/date-range-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/date-range-test.js index fdb089643c5f5..5a063933f6a9f 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/calendar/date-range-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/calendar/date-range-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ DaterangeTest = TestCase('DaterangeTest'); @@ -60,4 +60,4 @@ DaterangeTest.prototype.testDestroy = function() { assertEquals(true, dateRangeExist != dateRange.is(':mage-dateRange')); assertEquals(true, fromExist != from.hasClass('_has-datepicker')); assertEquals(true, toExist != to.hasClass('_has-datepicker')); -}; \ No newline at end of file +}; diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html index 3588b28732e10..f5340c915f415 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html @@ -2,7 +2,7 @@ /** * @category mage.collapsible * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -11,4 +11,4 @@

    Test text

    - \ No newline at end of file + diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html index a230f4cdb6d60..f8d32fbcd0bf5 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html @@ -2,7 +2,7 @@ /** * @category mage.collapsible * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js index 81efdd85efc8d..b6a73c243e14b 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js @@ -1,7 +1,7 @@ /** * @category mage.collapsible * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js index 8e1afbe2518b5..e09d2f5846646 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ DecoratorTest = TestCase('DecoratorTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html index 19b4febd21fd9..b1517906bc7fa 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html @@ -2,7 +2,7 @@ /** * @category mage.dropdown * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js b/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js index 383b06273f48e..c1514fb302942 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/edit_trigger/edit-trigger-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/edit_trigger/edit-trigger-test.js index b62aacdbbc234..b858b35c05ba5 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/edit_trigger/edit-trigger-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/edit_trigger/edit-trigger-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ EditTriggerTest = TestCase('EditTriggerTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/form/form-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/form/form-test.js index 59ece250beb79..4b618f45bcc92 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/form/form-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/form/form-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ FormTest = TestCase('FormTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/list/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/list/index.html index 45a6f82fcdc9e..229d8baa72232 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/list/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/list/index.html @@ -1,6 +1,6 @@ @@ -22,4 +22,4 @@
    - \ No newline at end of file + diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/list/jquery-list-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/list/jquery-list-test.js index 52913f91a9732..0f2b7a170914d 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/list/jquery-list-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/list/jquery-list-test.js @@ -1,7 +1,7 @@ /** * @category mage.loader * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ test('init & destroy', function() { diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/loader/jquery-loader-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/loader/jquery-loader-test.js index add3f2774c813..8b29c8d9b7182 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/loader/jquery-loader-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/loader/jquery-loader-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ TestCase('options', function() { @@ -70,4 +70,4 @@ TestCase( 'destroy', function() { element.loader('destroy'); equal( $('.loading-mask').is(':visible'), false, '.loader() destroyed'); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader-test.js index 5ee9b933353c9..95eea3a134e45 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ LoaderTest = TestCase('LoaderTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader.html b/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader.html index 587075286e672..af79963c37236 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/loader/loader.html @@ -1,6 +1,6 @@ @@ -22,4 +22,4 @@
    - \ No newline at end of file + diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/mage-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/mage-test.js index a0ad2222ccc20..37f3901e3b744 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/mage-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/mage-test.js @@ -1,9 +1,9 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ MageTest = TestCase('MageTest'); MageTest.prototype.setUp = function() { /*:DOC += */ -}; \ No newline at end of file +}; diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/menu/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/menu/index.html index 95450cb849e77..8e6db393e6dcb 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/menu/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/menu/index.html @@ -2,7 +2,7 @@ /** * @category mage.menu * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/menu/test-menu.js b/dev/tests/js/JsTestDriver/testsuite/mage/menu/test-menu.js index 57a87a14c3e49..ad8ae39c63280 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/menu/test-menu.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/menu/test-menu.js @@ -1,7 +1,7 @@ /** * @category mage.js * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/search/regular-search-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/search/regular-search-test.js index f0eda9d082376..32c7e425b4e1d 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/search/regular-search-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/search/regular-search-test.js @@ -1,7 +1,7 @@ /** * @category mage.js * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ //Code to be tested for /app/code/Magento/Search/view/frontend/form-mini.js (_onSubmit) diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/suggest/suggest-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/suggest/suggest-test.js index 2f17ecc00aabc..065e9ed0a66d0 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/suggest/suggest-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/suggest/suggest-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ SuggestTest = TestCase('SuggestTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/suggest/tree-suggest-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/suggest/tree-suggest-test.js index cffdc06c10533..a3657d8680ac8 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/suggest/tree-suggest-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/suggest/tree-suggest-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/tabs/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/tabs/index.html index 65defb9e707e5..316c098033c67 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/tabs/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/tabs/index.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs-test.js index b12bc8ab7746a..16d75863913dd 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ TabsTest = TestCase('TabsTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs.js b/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs.js index 1cfacb7acf4e0..3761e75fa6d90 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/tabs/tabs.js @@ -1,7 +1,7 @@ /** * @category mage.js * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js index de9acabc90947..021e13f0a3cef 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ TranslateTest = TestCase('TranslateTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline/translate-inline-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline/translate-inline-test.js index 300dc2b0a43f0..d3a4826f85661 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline/translate-inline-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/translate_inline/translate-inline-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ TranslateInlineTest = TestCase('TranslateInlineTest'); 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 index e9961cd512978..cba9e8527f3b0 100644 --- 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 @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ TranslateInlineDialogVdeTest = TestCase('TranslateInlineDialogVdeTest'); 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 index b17959e4f88a0..4dcd3fcd90eab 100644 --- 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 @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ TranslateInlineVdeTest = TestCase('TranslateInlineVdeTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/validation/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/validation/index.html index feaa72204f3b0..89ad8726bb81a 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/validation/index.html +++ b/dev/tests/js/JsTestDriver/testsuite/mage/validation/index.html @@ -2,7 +2,7 @@ /** * @category mage.validation * @package test - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> @@ -32,4 +32,4 @@
    - \ No newline at end of file + diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/validation/test-validation.js b/dev/tests/js/JsTestDriver/testsuite/mage/validation/test-validation.js index 58b2c628ca1d0..e105142d42336 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/validation/test-validation.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/validation/test-validation.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ test( "testValidateNoHtmlTags", function() { @@ -608,4 +608,4 @@ test( "testValidateDigitsRange", function() { ok($.validator.methods['validate-digits-range'].call(this, '15', el1, null)); ok(!$.validator.methods['validate-digits-range'].call(this, '1', el1, null)); ok(!$.validator.methods['validate-digits-range'].call(this, '30', el1, null)); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/webapi-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/webapi-test.js index 644576a16ac01..f4a1081aab7b5 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/webapi-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/webapi-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ WebapiTest = TestCase('WebapiTest'); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/zoom/zoom-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/zoom/zoom-test.js index 46d0d1227daa8..342f0c39d2130 100644 --- a/dev/tests/js/JsTestDriver/testsuite/mage/zoom/zoom-test.js +++ b/dev/tests/js/JsTestDriver/testsuite/mage/zoom/zoom-test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ ZoomTest = TestCase('ZoomTest'); @@ -334,4 +334,4 @@ ZoomTest.prototype.testGetAspectRatio = function() { assertNull(aspectRatio); aspectRatio = zoomInstance._getAspectRatio(jQuery('
    ', size)); assertEquals((Math.round((size.width / size.height) * 100) / 100), aspectRatio); -}; \ No newline at end of file +}; diff --git a/dev/tests/js/jasmine/assets/apply/components/fn.js b/dev/tests/js/jasmine/assets/apply/components/fn.js index 0a92f4799b05c..da37fe805b246 100644 --- a/dev/tests/js/jasmine/assets/apply/components/fn.js +++ b/dev/tests/js/jasmine/assets/apply/components/fn.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([], function () { diff --git a/dev/tests/js/jasmine/assets/apply/index.js b/dev/tests/js/jasmine/assets/apply/index.js index 000564aafcafe..64f066642d045 100644 --- a/dev/tests/js/jasmine/assets/apply/index.js +++ b/dev/tests/js/jasmine/assets/apply/index.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/assets/apply/templates/node.html b/dev/tests/js/jasmine/assets/apply/templates/node.html index 4a42567327395..260370525b89c 100644 --- a/dev/tests/js/jasmine/assets/apply/templates/node.html +++ b/dev/tests/js/jasmine/assets/apply/templates/node.html @@ -1,10 +1,10 @@
    ='<%= JSON.stringify(nodeData) %>'>
    -
    \ No newline at end of file +
    diff --git a/dev/tests/js/jasmine/assets/jsbuild/config.js b/dev/tests/js/jasmine/assets/jsbuild/config.js index 46c8d246f9137..4145998f16844 100644 --- a/dev/tests/js/jasmine/assets/jsbuild/config.js +++ b/dev/tests/js/jasmine/assets/jsbuild/config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define(function () { diff --git a/dev/tests/js/jasmine/assets/jsbuild/external.js b/dev/tests/js/jasmine/assets/jsbuild/external.js index 7836099a952a6..e500c569093e8 100644 --- a/dev/tests/js/jasmine/assets/jsbuild/external.js +++ b/dev/tests/js/jasmine/assets/jsbuild/external.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([], function () { diff --git a/dev/tests/js/jasmine/assets/jsbuild/local.js b/dev/tests/js/jasmine/assets/jsbuild/local.js index adb37196d1c89..53db06a73e97b 100644 --- a/dev/tests/js/jasmine/assets/jsbuild/local.js +++ b/dev/tests/js/jasmine/assets/jsbuild/local.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([], function () { diff --git a/dev/tests/js/jasmine/assets/script/index.js b/dev/tests/js/jasmine/assets/script/index.js index f945add10b49b..e708d6827ca30 100644 --- a/dev/tests/js/jasmine/assets/script/index.js +++ b/dev/tests/js/jasmine/assets/script/index.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/assets/script/templates/selector.html b/dev/tests/js/jasmine/assets/script/templates/selector.html index 4399a402b9275..fd3a65d5fb733 100644 --- a/dev/tests/js/jasmine/assets/script/templates/selector.html +++ b/dev/tests/js/jasmine/assets/script/templates/selector.html @@ -1,6 +1,6 @@ @@ -12,4 +12,4 @@ -
    \ No newline at end of file + diff --git a/dev/tests/js/jasmine/assets/script/templates/virtual.html b/dev/tests/js/jasmine/assets/script/templates/virtual.html index 2de6c79f77b8d..d2e5329c2c830 100644 --- a/dev/tests/js/jasmine/assets/script/templates/virtual.html +++ b/dev/tests/js/jasmine/assets/script/templates/virtual.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/js/jasmine/assets/text/config.js b/dev/tests/js/jasmine/assets/text/config.js index d20ecb0c87f40..b456aa0468460 100644 --- a/dev/tests/js/jasmine/assets/text/config.js +++ b/dev/tests/js/jasmine/assets/text/config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define(function () { @@ -8,11 +8,11 @@ define(function () { return { local: { path: 'text!tests/assets/text/local.html', - result: '\nLocal Template' + result: '\nLocal Template' }, external: { path: 'text!tests/assets/text/external.html', - result: '\nExternal Template' + result: '\nExternal Template' } }; }); diff --git a/dev/tests/js/jasmine/assets/text/external.html b/dev/tests/js/jasmine/assets/text/external.html index e86236ea312ad..d1cc2763b67b2 100644 --- a/dev/tests/js/jasmine/assets/text/external.html +++ b/dev/tests/js/jasmine/assets/text/external.html @@ -1,6 +1,6 @@ diff --git a/dev/tests/js/jasmine/assets/text/local.html b/dev/tests/js/jasmine/assets/text/local.html index 9e6a10a534aaa..442fd26c7afc0 100644 --- a/dev/tests/js/jasmine/assets/text/local.html +++ b/dev/tests/js/jasmine/assets/text/local.html @@ -1,7 +1,7 @@ -Local Template \ No newline at end of file +Local Template diff --git a/dev/tests/js/jasmine/assets/tools.js b/dev/tests/js/jasmine/assets/tools.js index 5945be8d06474..32ed8d366325b 100644 --- a/dev/tests/js/jasmine/assets/tools.js +++ b/dev/tests/js/jasmine/assets/tools.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/require.conf.js b/dev/tests/js/jasmine/require.conf.js index 9ba59b81bc27f..f069042a98aa3 100644 --- a/dev/tests/js/jasmine/require.conf.js +++ b/dev/tests/js/jasmine/require.conf.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -16,17 +16,23 @@ require.config({ ] }, paths: { - 'tests': 'dev/tests/js/jasmine' + 'tests': 'dev/tests/js/jasmine', + 'squire': 'node_modules/squirejs/src/Squire' + }, + shim: { + squire: { + exports: 'squire' + } }, config: { jsbuild: { 'dev/tests/js/jasmine/assets/jsbuild/local.js': 'define([], function () {\'use strict\'; return \'internal module\'; });' }, text: { - 'dev/tests/js/jasmine/assets/text/local.html': '\nLocal Template' + 'dev/tests/js/jasmine/assets/text/local.html': '\nLocal Template' } }, deps: [ 'mage/requirejs/static' ] -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/spec_runner/index.js b/dev/tests/js/jasmine/spec_runner/index.js index ce57b6c354cb9..625b75a7c3e84 100644 --- a/dev/tests/js/jasmine/spec_runner/index.js +++ b/dev/tests/js/jasmine/spec_runner/index.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -13,38 +13,14 @@ function init(grunt, options) { stripJsonComments = require('strip-json-comments'), path = require('path'), config, - themes; - + themes, + file; + config = grunt.file.read(__dirname + '/settings.json'); config = stripJsonComments(config); config = JSON.parse(config); - //themes = require(path.resolve(process.cwd(), config.themes)); - //TODO: MAGETWO-39843 - themes = { - blank: { - area: 'frontend', - name: 'Magento/blank', - locale: 'en_US', - files: [ - 'css/styles-m', - 'css/styles-l', - 'css/email', - 'css/email-inline' - ], - dsl: 'less' - }, - backend: { - area: 'adminhtml', - name: 'Magento/backend', - locale: 'en_US', - files: [ - 'css/styles-old', - 'css/styles' - ], - dsl: 'less' - } - } + themes = require(path.resolve(process.cwd(), config.themes)); if (options.theme) { themes = _.pick(themes, options.theme); @@ -54,6 +30,12 @@ function init(grunt, options) { config.themes = themes; + file = grunt.option('file'); + + if (file) { + config.singleTest = file; + } + enableTasks(grunt, config); } @@ -84,4 +66,4 @@ function getTasks() { module.exports = { init: init, getTasks: getTasks -}; \ No newline at end of file +}; diff --git a/dev/tests/js/jasmine/spec_runner/settings.json b/dev/tests/js/jasmine/spec_runner/settings.json index 109da479146da..25407123c1f34 100644 --- a/dev/tests/js/jasmine/spec_runner/settings.json +++ b/dev/tests/js/jasmine/spec_runner/settings.json @@ -57,7 +57,8 @@ "^\/_SpecRunner.html", "^\/dev\/tests", "^\/.grunt", - "^\/pub\/static" + "^\/pub\/static", + "^\/node_modules" ], "options": { /** diff --git a/dev/tests/js/jasmine/spec_runner/tasks/connect.js b/dev/tests/js/jasmine/spec_runner/tasks/connect.js index 4d27b8c0be7fd..9134e84573c12 100644 --- a/dev/tests/js/jasmine/spec_runner/tasks/connect.js +++ b/dev/tests/js/jasmine/spec_runner/tasks/connect.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -61,4 +61,4 @@ function getTasks() { module.exports = { init: init, getTasks: getTasks -}; \ No newline at end of file +}; diff --git a/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js b/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js index 5d520860f4410..75a27fcb387c4 100644 --- a/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js +++ b/dev/tests/js/jasmine/spec_runner/tasks/jasmine.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -16,7 +16,6 @@ function init(config) { root = config.root; port = config.port; files = config.files; - host = _.template(config.host)({ port: port }); themes = config.themes; _.each(themes, function (themeData, themeName) { @@ -26,7 +25,13 @@ function init(config) { _.extend(themeData, { root: root }); + host = _.template(config.host)({ port: port++ }); render = renderTemplate.bind(null, themeData); + + if (config.singleTest) { + files.specs = [config.singleTest]; + } + specs = files.specs.map(render); specs = expand(specs).map(cutJsExtension); configs = files.requirejsConfigs.map(render); @@ -37,6 +42,10 @@ function init(config) { host: host, template: render(files.template), vendor: files.requireJs, + junit: { + path: "var/log/js-unit/", + consolidate: true + }, /** * @todo rename "helpers" to "specs" (implies overriding grunt-contrib-jasmine code) @@ -62,4 +71,4 @@ function getTasks() { module.exports = { init: init, getTasks: getTasks -}; \ No newline at end of file +}; diff --git a/dev/tests/js/jasmine/spec_runner/template.html b/dev/tests/js/jasmine/spec_runner/template.html index 3d3f61913da54..30f7138266614 100644 --- a/dev/tests/js/jasmine/spec_runner/template.html +++ b/dev/tests/js/jasmine/spec_runner/template.html @@ -1,6 +1,6 @@ @@ -27,4 +27,4 @@ - \ No newline at end of file + diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js new file mode 100644 index 0000000000000..6281dc3aaa6c0 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js @@ -0,0 +1,127 @@ +/** + * Copyright © 2013-2017 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +/* global jQuery */ +/* eslint-disable max-nested-callbacks */ +define([ + 'jquery', + 'squire' +], function ($, Squire) { + 'use strict'; + + var injector = new Squire(), + mocks = { + 'Magento_Ui/js/modal/alert': jasmine.createSpy(), + 'uiRegistry': jasmine.createSpy() + }, + obj; + + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Analytics/js/modal/modal-component'], function (Constr) { + obj = new Constr({ + provider: 'provName', + name: '', + index: '', + links: '', + listens: '', + + /** + * @return {Object} source - mock for form data + */ + form: function () { + return { + source: { + data: {} + } + }; + } + }); + done(); + }); + }); + + describe('Magento_Analytics/js/modal/modal-component', function () { + describe('"sendPostponeRequest" method', function () { + it('should send a ajax request', function () { + spyOn(jQuery, 'ajax').and.callFake(function () { + var d = $.Deferred(); + + d.resolve({ + 'success': true + }); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + }); + + it('should call "onError" method if ajax received error', function () { + spyOn(obj, 'onError'); + spyOn(jQuery, 'ajax').and.callFake(function () { + var d = $.Deferred(); + + d.resolve({ + 'error': true + }); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + expect(obj.onError).toHaveBeenCalled(); + }); + + it('should call "onError" method if request failed', function () { + spyOn(obj, 'onError'); + spyOn(jQuery, 'ajax').and.callFake(function () { + var d = $.Deferred(); + + d.reject(); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + expect(obj.onError).toHaveBeenCalled(); + }); + }); + + describe('"onError" method', function () { + var abortRequest = { + statusText: 'abort' + }, + errorRequest = { + error: true, + message: 'Error text' + }; + + it('should do nothing if request aborted', function () { + expect(obj.onError(abortRequest)).toBeUndefined(); + }); + + it('should show alert with error', function () { + obj.onError(errorRequest); + expect(mocks['Magento_Ui/js/modal/alert']).toHaveBeenCalled(); + }); + }); + + describe('"actionCancel" method', function () { + it('should call "sendPostponeRequest" and "closeModal" methods', function () { + spyOn(obj, 'sendPostponeRequest'); + spyOn(obj, 'closeModal'); + obj.actionCancel(); + expect(obj.sendPostponeRequest).toHaveBeenCalledWith(obj.postponeOptions); + expect(obj.closeModal).toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/utils/percentage-price-calculator.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/utils/percentage-price-calculator.test.js new file mode 100644 index 0000000000000..22e73621c3e2b --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/utils/percentage-price-calculator.test.js @@ -0,0 +1,67 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define(['Magento_Catalog/js/utils/percentage-price-calculator'], function (percentagePriceCalculator) { + 'use strict'; + + var basePrice = 100, + negativeBasePrice = -10, + decimalBasePrice = '100,1', + zeroBasePrice = 0; + + describe('Check valid calculation', function () { + it('5%', function () { + expect(percentagePriceCalculator(basePrice, '5%')).toBe('95.00'); + }); + it('0%', function () { + expect(percentagePriceCalculator(basePrice, '0%')).toBe('100.00'); + }); + it('100%', function () { + expect(percentagePriceCalculator(basePrice, '100%')).toBe('0.00'); + }); + it('110%', function () { + expect(percentagePriceCalculator(basePrice, '110%')).toBe('0.00'); + }); + it('5.5%', function () { + expect(percentagePriceCalculator(basePrice, '5.5%')).toBe('94.50'); + }); + it('.5%', function () { + expect(percentagePriceCalculator(basePrice, '.5%')).toBe('99.50'); + }); + it('-7%', function () { + expect(percentagePriceCalculator(basePrice, '-7%')).toBe('107.00'); + }); + }); + + describe('Check invalid input calculation', function () { + it('invalid with %', function () { + expect(percentagePriceCalculator(basePrice, '7p%')).toBe(''); + expect(percentagePriceCalculator(basePrice, '-%')).toBe(''); + }); + it('without %', function () { + expect(percentagePriceCalculator(basePrice, '7p')).toBe('7p'); + expect(percentagePriceCalculator(basePrice, '0')).toBe('0'); + expect(percentagePriceCalculator(basePrice, 'qwe')).toBe('qwe'); + }); + it('just %', function () { + expect(percentagePriceCalculator(basePrice, '%')).toBe(''); + }); + it('empty', function () { + expect(percentagePriceCalculator(basePrice, '')).toBe(''); + }); + }); + + describe('Other', function () { + it('negative base price', function () { + expect(percentagePriceCalculator(negativeBasePrice, '10%')).toBe('-9.00'); + }); + it('decimal base price', function () { + expect(percentagePriceCalculator(decimalBasePrice, '10%')).toBe('90.09'); + }); + it('zero base price', function () { + expect(percentagePriceCalculator(zeroBasePrice, '10%')).toBe('0.00'); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/new-customer-address.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/new-customer-address.test.js new file mode 100644 index 0000000000000..325a63a670380 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/new-customer-address.test.js @@ -0,0 +1,74 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Checkout/js/model/new-customer-address' +], function (NewCustomerAddress) { + 'use strict'; + + describe('Magento_Checkout/js/model/new-customer-address', function () { + var newCustomerAddress; + + window.checkoutConfig = { + defaultCountryId: 'US' + }; + + beforeEach(function () { + newCustomerAddress = NewCustomerAddress; + }); + + it('Check that is executable.', function () { + expect(typeof newCustomerAddress).toEqual('function'); + }); + + it('Check on empty object.', function () { + var expected = { + countryId: 'US', + regionCode: null, + region: null + }; + + expect(JSON.stringify(newCustomerAddress({}))).toEqual(JSON.stringify(expected)); + }); + + it('Check on function call with empty address data.', function () { + var result = newCustomerAddress({}); + + expect(result.isDefaultShipping()).toBeUndefined(); + expect(result.isDefaultBilling()).toBeUndefined(); + expect(result.getType()).toEqual('new-customer-address'); + expect(result.getKey()).toEqual('new-customer-address'); + expect(result.getKey()).toContain('new-customer-address'); + expect(result.isEditable()).toBeTruthy(); + expect(result.canUseForBilling()).toBeTruthy(); + }); + + it('Check on regionId with region object in address data.', function () { + var result = newCustomerAddress({ + region: { + 'region_id': 1 + } + }), + expected = { + countryId: 'US', + regionId: 1 + }; + + expect(JSON.stringify(result)).toEqual(JSON.stringify(expected)); + }); + it('Check on regionId with countryId in address data.', function () { + var result = newCustomerAddress({ + 'country_id': 'US' + }), + expected = { + countryId: 'US', + regionCode: null, + region: null + }; + + expect(JSON.stringify(result)).toEqual(JSON.stringify(expected)); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/view/cart/shipping-estimation.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/view/cart/shipping-estimation.test.js new file mode 100644 index 0000000000000..1ffb12126203d --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/view/cart/shipping-estimation.test.js @@ -0,0 +1,115 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint max-nested-callbacks: 0 */ + +define(['squire', 'ko'], function (Squire, ko) { + 'use strict'; + + var injector = new Squire(), + checkoutProvider = { + on: jasmine.createSpy() + }, + mocks = { + 'Magento_Checkout/js/action/select-shipping-address': jasmine.createSpy(), + 'Magento_Checkout/js/model/address-converter': { + formAddressDataToQuoteAddress: jasmine.createSpy() + }, + 'Magento_Checkout/js/model/cart/estimate-service': jasmine.createSpy(), + 'Magento_Checkout/js/checkout-data': jasmine.createSpy(), + 'Magento_Checkout/js/model/shipping-rates-validator': { + bindChangeHandlers: jasmine.createSpy() + }, + 'uiRegistry': { + async: jasmine.createSpy().and.returnValue(function (callback) { + callback(checkoutProvider); + }), + create: jasmine.createSpy(), + get: jasmine.createSpy(), + set: jasmine.createSpy() + }, + 'Magento_Checkout/js/model/quote': { + isVirtual: jasmine.createSpy(), + shippingAddress: jasmine.createSpy() + }, + 'Magento_Checkout/js/model/checkout-data-resolver': { + resolveEstimationAddress: jasmine.createSpy() + }, + 'mage/validation': jasmine.createSpy() + }, + obj; + + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Checkout/js/view/cart/shipping-estimation'], function (Constr) { + obj = new Constr({ + provider: 'provName', + name: '', + index: '' + }); + done(); + }); + }); + + describe('Magento_Checkout/js/view/cart/shipping-estimation', function () { + describe('"initElement" method', function () { + it('Check for return value and element that initiated.', function () { + var element = jasmine.createSpyObj('element', ['initContainer']); + + expect(obj.initElement(element)).toBe(obj); + expect(mocks['Magento_Checkout/js/model/shipping-rates-validator'].bindChangeHandlers) + .not.toHaveBeenCalled(); + }); + it('Check shipping rates validator call.', function () { + var element = { + index: 'address-fieldsets', + elems: ko.observable(), + initContainer: jasmine.createSpy() + }; + + spyOn(element.elems, 'subscribe'); + + obj.initElement(element); + expect(mocks['Magento_Checkout/js/model/shipping-rates-validator'].bindChangeHandlers) + .toHaveBeenCalledWith(element.elems(), true, 500); + expect(element.elems.subscribe) + .toHaveBeenCalledWith(jasmine.any(Function)); + }); + }); + + describe('"getEstimationInfo" method', function () { + it('Check for invalid form data.', function () { + obj.source = { + get: jasmine.createSpy().and.returnValue(true), + set: jasmine.createSpy(), + trigger: jasmine.createSpy() + }; + + expect(obj.getEstimationInfo()).toBeUndefined(); + expect(obj.source.get).toHaveBeenCalledWith('params.invalid'); + expect(obj.source.get).not.toHaveBeenCalledWith('shippingAddress'); + expect(obj.source.set).toHaveBeenCalledWith('params.invalid', false); + expect(obj.source.trigger).toHaveBeenCalledWith('shippingAddress.data.validate'); + expect(mocks['Magento_Checkout/js/action/select-shipping-address']).not.toHaveBeenCalled(); + obj.source = {}; + }); + it('Check for vaild form data.', function () { + obj.source = { + get: jasmine.createSpy().and.returnValues(false, {}), + set: jasmine.createSpy(), + trigger: jasmine.createSpy() + }; + + expect(obj.getEstimationInfo()).toBeUndefined(); + expect(obj.source.get).toHaveBeenCalledWith('params.invalid'); + expect(obj.source.get).toHaveBeenCalledWith('shippingAddress'); + expect(obj.source.set).toHaveBeenCalledWith('params.invalid', false); + expect(obj.source.trigger).toHaveBeenCalledWith('shippingAddress.data.validate'); + expect(mocks['Magento_Checkout/js/action/select-shipping-address']).toHaveBeenCalled(); + obj.source = {}; + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/view/shipping.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/view/shipping.test.js new file mode 100644 index 0000000000000..03fa401b3f11a --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/view/shipping.test.js @@ -0,0 +1,194 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint max-nested-callbacks: 0 */ +require.config({ + map: { + '*': { + 'Magento_Checkout/js/view/shipping': 'Magento_Checkout/js/view/shipping' + } + } +}); + +define(['squire', 'ko', 'jquery', 'jquery/validate'], function (Squire, ko, $) { + 'use strict'; + + var injector = new Squire(), + modalStub = { + openModal: jasmine.createSpy(), + closeModal: jasmine.createSpy() + }, + mocks = { + 'Magento_Customer/js/model/customer': { + isLoggedIn: ko.observable() + }, + 'Magento_Customer/js/model/address-list': ko.observableArray(), + 'Magento_Checkout/js/model/address-converter': jasmine.createSpy(), + 'Magento_Checkout/js/model/quote': { + isVirtual: jasmine.createSpy(), + shippingMethod: ko.observable() + }, + 'Magento_Checkout/js/action/create-shipping-address': jasmine.createSpy().and.returnValue( + jasmine.createSpyObj('newShippingAddress', ['getKey']) + ), + 'Magento_Checkout/js/action/select-shipping-address': jasmine.createSpy(), + 'Magento_Checkout/js/model/shipping-rates-validator': jasmine.createSpy(), + 'Magento_Checkout/js/model/shipping-address/form-popup-state': { + isVisible: ko.observable() + }, + 'Magento_Checkout/js/model/shipping-service': jasmine.createSpyObj('service', ['getShippingRates']), + 'Magento_Checkout/js/action/select-shipping-method': jasmine.createSpy(), + 'Magento_Checkout/js/model/shipping-rate-registry': jasmine.createSpy(), + 'Magento_Checkout/js/action/set-shipping-information': jasmine.createSpy(), + 'Magento_Checkout/js/model/step-navigator': jasmine.createSpyObj('navigator', ['registerStep']), + 'Magento_Ui/js/modal/modal': jasmine.createSpy('modal').and.returnValue(modalStub), + 'Magento_Checkout/js/model/checkout-data-resolver': jasmine.createSpyObj( + 'dataResolver', + ['resolveShippingAddress'] + ), + 'Magento_Checkout/js/checkout-data': jasmine.createSpyObj( + 'checkoutData', + ['setSelectedShippingAddress', 'setNewCustomerShippingAddress', 'setSelectedShippingRate'] + ), + 'uiRegistry': jasmine.createSpy(), + 'Magento_Checkout/js/model/shipping-rate-service': jasmine.createSpy() + }, + obj; + + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Checkout/js/view/shipping'], function (Constr) { + obj = new Constr({ + provider: 'provName', + name: '', + index: '', + popUpForm: { + options: { + buttons: { + save: {}, + cancel: {} + } + } + } + }); + done(); + }); + }); + + describe('Magento_Checkout/js/view/shipping', function () { + describe('"navigate" method', function () { + it('Check for return value.', function () { + expect(obj.navigate()).toBeUndefined(); + }); + }); + + describe('"getPopUp" method', function () { + it('Check for return value.', function () { + expect(obj.getPopUp()).toBe(modalStub); + expect(mocks['Magento_Ui/js/modal/modal']).toHaveBeenCalled(); + mocks['Magento_Ui/js/modal/modal'].calls.reset(); + }); + it('Check on single modal call', function () { + expect(obj.getPopUp()).toBe(modalStub); + expect(mocks['Magento_Ui/js/modal/modal']).not.toHaveBeenCalled(); + }); + }); + + describe('"showFormPopUp" method', function () { + it('Check method call.', function () { + expect(obj.showFormPopUp()).toBeUndefined(); + expect(obj.isFormPopUpVisible()).toBeTruthy(); + expect(modalStub.openModal).toHaveBeenCalled(); + }); + }); + + describe('"saveNewAddress" method', function () { + it('Check method call with invalid form data.', function () { + obj.source = { + get: jasmine.createSpy().and.returnValue(true), + set: jasmine.createSpy(), + trigger: jasmine.createSpy() + }; + + expect(obj.saveNewAddress()).toBeUndefined(); + expect(obj.isNewAddressAdded()).toBeFalsy(); + expect(modalStub.closeModal).not.toHaveBeenCalled(); + }); + it('Check method call with valid form data.', function () { + obj.source = { + get: jasmine.createSpy().and.returnValues(true, false, {}), + set: jasmine.createSpy(), + trigger: jasmine.createSpy() + }; + + expect(obj.saveNewAddress()).toBeUndefined(); + expect(obj.isNewAddressAdded()).toBeTruthy(); + expect(modalStub.closeModal).toHaveBeenCalled(); + }); + }); + + describe('"selectShippingMethod" method', function () { + it('Check method call.', function () { + var shippingMethod = { + 'carrier_code': 'carrier', + 'method_code': 'method' + }; + + expect(obj.selectShippingMethod(shippingMethod)).toBeTruthy(); + expect(mocks['Magento_Checkout/js/checkout-data'].setSelectedShippingRate) + .toHaveBeenCalledWith('carrier_method'); + }); + }); + + describe('"setShippingInformation" method', function () { + it('Check method call.', function () { + expect(obj.setShippingInformation()).toBeUndefined(); + }); + }); + + describe('"validateShippingInformation" method', function () { + it('Check method call on negative cases.', function () { + obj.source = { + get: jasmine.createSpy().and.returnValue(true), + set: jasmine.createSpy(), + trigger: jasmine.createSpy() + }; + + expect(obj.validateShippingInformation()).toBeFalsy(); + expect(obj.errorValidationMessage()).toBe('Please specify a shipping method.'); + spyOn(mocks['Magento_Checkout/js/model/quote'], 'shippingMethod').and.returnValue(true); + spyOn(mocks['Magento_Customer/js/model/customer'], 'isLoggedIn').and.returnValue(true); + expect(obj.validateShippingInformation()).toBeFalsy(); + }); + it('Check method call on positive case.', function () { + $('body').append('
    ' + + '' + + ''); + obj.source = { + get: jasmine.createSpy().and.returnValue(true), + set: jasmine.createSpy(), + trigger: jasmine.createSpy() + }; + obj.isFormInline = false; + + spyOn(mocks['Magento_Checkout/js/model/quote'], 'shippingMethod').and.returnValue(true); + spyOn(mocks['Magento_Customer/js/model/customer'], 'isLoggedIn').and.returnValue(false); + spyOn($.fn, 'valid').and.returnValue(true); + expect(obj.validateShippingInformation()).toBeTruthy(); + }); + }); + + describe('"triggerShippingDataValidateEvent" method', function () { + it('Check method call.', function () { + obj.source = { + get: jasmine.createSpy().and.returnValue(true), + set: jasmine.createSpy(), + trigger: jasmine.createSpy() + }; + expect(obj.triggerShippingDataValidateEvent()).toBeUndefined(); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Customer/frontend/js/model/customer/address.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/frontend/js/model/customer/address.test.js new file mode 100644 index 0000000000000..f79ef3e5139b9 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/frontend/js/model/customer/address.test.js @@ -0,0 +1,58 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Customer/js/model/customer/address' +], function (CustomerAddress) { + 'use strict'; + + describe('Magento_Customer/js/model/customer/address', function () { + var customerAddress; + + beforeEach(function () { + customerAddress = CustomerAddress; + }); + + it('Check that is executable.', function () { + expect(typeof customerAddress).toEqual('function'); + }); + + it('Check on empty object.', function () { + var addressData = { + region: {} + }; + + expect(JSON.stringify(customerAddress(addressData))).toEqual(JSON.stringify({})); + }); + + it('Check on function call with empty address data.', function () { + var result = customerAddress({ + region: {} + }); + + expect(result.isDefaultShipping()).toBeUndefined(); + expect(result.isDefaultBilling()).toBeUndefined(); + expect(result.getAddressInline()).toBeUndefined(); + expect(result.getType()).toEqual('customer-address'); + expect(result.getKey()).toContain('customer-address'); + expect(result.getCacheKey()).toContain('customer-address'); + expect(result.isEditable()).toBeFalsy(); + expect(result.canUseForBilling()).toBeTruthy(); + }); + + it('Check on regionId with region object in address data.', function () { + var result = customerAddress({ + region: { + 'region_id': 1 + } + }), + expected = { + regionId: '1' + }; + + expect(JSON.stringify(result)).toEqual(JSON.stringify(expected)); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Customer/frontend/js/view/authentication-popup.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/frontend/js/view/authentication-popup.test.js new file mode 100644 index 0000000000000..4e830f8aad426 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/frontend/js/view/authentication-popup.test.js @@ -0,0 +1,81 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint max-nested-callbacks: 0 */ +define(['squire'], function (Squire) { + 'use strict'; + + var injector = new Squire(), + loginAction = jasmine.createSpy(), + mocks = { + 'Magento_Customer/js/action/login': loginAction, + 'Magento_Customer/js/customer-data': { + get: jasmine.createSpy() + }, + 'Magento_Customer/js/model/authentication-popup': { + createPopUp: jasmine.createSpy(), + modalWindow: null + }, + 'Magento_Ui/js/modal/alert': jasmine.createSpy(), + 'mage/url': jasmine.createSpyObj('customerData', ['setBaseUrl']) + }, + obj; + + loginAction.registerLoginCallback = jasmine.createSpy(); + window.authenticationPopup = { + customerRegisterUrl: 'register_url', + customerForgotPasswordUrl: 'forgot_password_url', + autocomplete: 'autocomplete_flag', + baseUrl: 'base_url' + }; + + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Customer/js/view/authentication-popup'], function (Constr) { + obj = new Constr({ + provider: 'provName', + name: '', + index: '' + }); + done(); + }); + }); + + describe('Magento_Customer/js/view/authentication-popup', function () { + describe('"isActive" method', function () { + it('Check for return value.', function () { + mocks['Magento_Customer/js/customer-data'].get.and.returnValue(function () { + return true; + }); + expect(obj.isActive()).toBeFalsy(); + }); + }); + }); + + describe('Magento_Customer/js/view/authentication-popup', function () { + describe('"setModalElement" method', function () { + it('Check for return value.', function () { + expect(obj.setModalElement()).toBeUndefined(); + expect(mocks['Magento_Customer/js/model/authentication-popup'].createPopUp).toHaveBeenCalled(); + }); + }); + }); + + describe('Magento_Customer/js/view/authentication-popup', function () { + describe('"login" method', function () { + it('Check for return value.', function () { + var event = { + currentTarget: '
    ', + stopPropagation: jasmine.createSpy() + }; + + expect(obj.login(null, event)).toBeFalsy(); + expect(mocks['Magento_Customer/js/action/login']).toHaveBeenCalledWith({ + username: 'customer' + }); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Msrp/frontend/js/msrp.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Msrp/frontend/js/msrp.test.js index bcb99deaff20f..4f28934c874ef 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Msrp/frontend/js/msrp.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Msrp/frontend/js/msrp.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js index 1fba5d18e9b60..500787f844004 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/PageCache/frontend/js/page-cache.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Review/view/frontend/web/js/process-review.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Review/view/frontend/web/js/process-review.test.js new file mode 100644 index 0000000000000..58b254db52349 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Review/view/frontend/web/js/process-review.test.js @@ -0,0 +1,76 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/*eslint max-nested-callbacks: 0*/ +/*jscs:disable jsDoc*/ + +define([ + 'jquery', + 'Magento_Review/js/process-reviews' +], function ($, reviewProcessor) { + 'use strict'; + + describe('Test product page reviews processor', function () { + var element, + config = { + reviewsTabSelector: '#review-tab' + }; + + beforeEach(function () { + element = $(''); + + $('body').append(element); + }); + + afterEach(function () { + element.remove(); + }); + + it('Should automatically load reviews after page load if review tab is active', function () { + element.addClass('active'); + + spyOn($, 'ajax').and.callFake(function () { + var d = $.Deferred(); + + d.promise().complete = function () {}; + + return d.promise(); + }); + + reviewProcessor(config, null); + + expect($.ajax).toHaveBeenCalled(); + }); + + it('Should not automatically load reviews after page load if review tab is not active', function () { + spyOn($, 'ajax').and.callFake(function () { + var d = $.Deferred(); + + d.promise().complete = function () {}; + + return d.promise(); + }); + + reviewProcessor(config, null); + + expect($.ajax).not.toHaveBeenCalled(); + }); + + it('Should load reviews if non active review tab was opened', function () { + spyOn($, 'ajax').and.callFake(function () { + var d = $.Deferred(); + + d.promise().complete = function () {}; + + return d.promise(); + }); + + reviewProcessor(config, null); + element.trigger('beforeOpen'); + + expect($.ajax).toHaveBeenCalled(); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/core/layout.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/core/layout.test.js index 748a1dd5333f5..656185c5af5c0 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/core/layout.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/core/layout.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -18,4 +18,4 @@ define([ expect(typeof layoutObj).toEqual("function"); }); }); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/adapter.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/adapter.test.js index c3b20b0af59e6..595e97ff2c089 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/adapter.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/adapter.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/client.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/client.test.js index 06da0e0ce2db0..3493d0bdd8a0f 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/client.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/client.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -10,17 +10,22 @@ define([ 'underscore', 'uiRegistry', - 'Magento_Ui/js/form/client' -], function (_, registry, Constr) { + 'Magento_Ui/js/form/client', + 'jquery', + 'mageUtils', + 'jquery/ui' +], function (_, registry, Constr, $, utils) { 'use strict'; describe('Magento_Ui/js/form/client', function () { - var obj = new Constr({ - provider: 'provName', - name: '', - index: '' - }); + provider: 'provName', + name: '', + index: '' + }), + jQueryMethods = {}; + + window.FORM_KEY = 'magentoFormKey'; registry.set('provName', { on: function () { @@ -31,6 +36,12 @@ define([ } }); + afterEach(function () { + _.each(jQueryMethods, function (value, key) { + $.fn[key] = value; + }); + }); + describe('"save" method', function () { it('Check for defined ', function () { expect(obj.hasOwnProperty('save')).toBeDefined(); @@ -50,7 +61,101 @@ define([ expect(type).toEqual('object'); }); + it('Check "beforeSave" method. ' + + 'Check calls "filterFormData", "serialize" and "ajax" inside themselves.', function () { + var data = { + key: { + anotherKey: 'value' + }, + anotherKey: [] + }, + params; + + obj.urls.beforeSave = 'requestPath'; + obj.selectorPrefix = 'selectorPrefix'; + obj.messagesClass = 'messagesClass'; + + params = { + url: obj.urls.beforeSave, + data: _.extend(data, { + form_key: 'magentoFormKey' + }), + success: jasmine.any(Function), + complete: jasmine.any(Function) + }; + + utils.filterFormData = jasmine.createSpy().and.returnValue(data); + utils.serialize = jasmine.createSpy().and.returnValue(data); + + $.ajax = jasmine.createSpy(); + obj.save(data); + expect(utils.filterFormData).toHaveBeenCalledWith(data); + expect(utils.serialize).toHaveBeenCalledWith(data); + expect($.ajax).toHaveBeenCalledWith(params); + + }); + it('Check call "beforeSave" method without parameters', function () { + $.ajax = jasmine.createSpy(); + obj.urls.beforeSave = null; + obj.save(); + + expect($.ajax).not.toHaveBeenCalled(); + }); + it('Check call "beforeSave" method. Check "success" ajax callback with success response.' , function () { + var request; + + $.ajax = jasmine.createSpy().and.callFake(function (req) { + request = req.success; + }); + $.fn.notification = jasmine.createSpy(); + obj.urls.beforeSave = 'requestPath'; + obj.save(); + + expect(request({error: false})).toBe(true); + expect($('body').notification).not.toHaveBeenCalledWith('clear'); + }); + + it('Check call "beforeSave" method. Check "success" ajax callback with error response.' , function () { + var request, + notificationArguments; + + $.ajax = jasmine.createSpy().and.callFake(function (req) { + request = req.success; + }); + jQueryMethods.notification = $.fn.notification; + $.fn.notification = jasmine.createSpy(); + obj.urls.beforeSave = 'requestPath'; + obj.save(); + + notificationArguments = { + error: true, + message: 1, + insertMethod: jasmine.any(Function) + }; + + expect(request({ + error: true, + messages: [1] + })).toBeUndefined(); + expect($('body').notification.calls.allArgs()).toEqual([['clear'], ['add', notificationArguments]]); + }); + it('Check call "beforeSave" method. Check "complete" ajax callback.' , function () { + var request; + + $.ajax = jasmine.createSpy().and.callFake(function (req) { + request = req.complete; + }); + + jQueryMethods.trigger = $.fn.trigger; + $.fn.trigger = jasmine.createSpy(); + obj.urls.beforeSave = 'requestPath'; + obj.save(); + + expect(request()).toBeUndefined(); + expect($('body').trigger).toHaveBeenCalledWith('processStop'); + }); }); + describe('"initialize" method', function () { it('Check for defined ', function () { expect(obj.hasOwnProperty('initialize')).toBeDefined(); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/area.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/area.test.js index 7ba3972f5bb06..2e4238aa62a05 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/area.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/area.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection.test.js index 9d0aa62d67eab..53d487aec4b6e 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js index 806964352be5f..45da8dafc57a0 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/collection/item.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -21,38 +21,6 @@ define([ index: '' }); - registry.set('provName', { - on: function () { - }, - get: function () { - }, - set: function () { - } - }); - - describe('"initProperties" method', function () { - it('Check for defined ', function () { - expect(obj.hasOwnProperty('initProperties')).toBeDefined(); - }); - it('Check answer type', function () { - var type = typeof obj.initProperties; - - expect(type).toEqual('function'); - }); - it('Check returned value if method called without arguments', function () { - expect(obj.initProperties()).toBeDefined(); - }); - it('Check returned value type if method called without arguments', function () { - var type = typeof obj.initProperties(); - - expect(type).toEqual('object'); - }); - it('Check "displayed" property', function () { - obj.displayed = null; - obj.initProperties(); - expect(obj.displayed).toEqual([]); - }); - }); describe('"initObservable" method', function () { it('Check for defined ', function () { expect(obj.hasOwnProperty('initObservable')).toBeDefined(); @@ -178,16 +146,23 @@ define([ prefix: 'magento' }; + obj.getPreview = jasmine.createSpy().and.callFake(function () { + return []; + }); + expect(obj.buildPreview(arg)).toBeDefined(); }); it('Check returned value type if method called with object argument', function () { var arg = { items: [], prefix: 'magento' - }, - type = typeof obj.buildPreview(arg); + }; + + obj.getPreview = jasmine.createSpy().and.callFake(function () { + return []; + }); - expect(type).toEqual('string'); + expect(typeof obj.buildPreview(arg)).toEqual('string'); }); it('Check called "this.getPreview" method with object argument', function () { var arg = { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/group.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/group.test.js index efeca14c3271b..f417b5f884e0a 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/group.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/group.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/html.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/html.test.js index dfdf0fea34d76..18a3ef789842b 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/html.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/html.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js index 56449c04406a0..e9d4d4cdf8274 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -56,23 +56,6 @@ define([ expect(obj.observe).toHaveBeenCalled(); }); }); - describe('"onUniqueUpdate" method', function () { - it('Check for defined ', function () { - expect(obj.hasOwnProperty('onUniqueUpdate')).toBeDefined(); - }); - it('Check method type', function () { - var type = typeof obj.onUniqueUpdate; - - expect(type).toEqual('function'); - }); - it('Check called "this.trigger" inner onUniqueUpdate method', function () { - obj.trigger = jasmine.createSpy().and.callFake(function () { - return obj; - }); - obj.onUniqueUpdate(); - expect(obj.trigger).toHaveBeenCalled(); - }); - }); describe('"activate" method', function () { it('Check for defined ', function () { expect(obj.hasOwnProperty('activate')).toBeDefined(); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js index 173e803b14a21..cc89e9abec67e 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/components/tab_group.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -23,14 +23,6 @@ define([ }); window.FORM_KEY = 'magentoFormKey'; - registry.set('provName', { - on: function () { - }, - get: function () { - }, - set: function () { - } - }); describe('"initElement" method', function () { it('Check for defined ', function () { @@ -48,6 +40,8 @@ define([ on: function () { }, active: function () { + }, + activate: function () { } }; @@ -60,6 +54,8 @@ define([ on: function () { }, active: function () { + }, + activate: function () { } }, type = typeof obj.initElement(arg); @@ -83,6 +79,8 @@ define([ on: function () { }, active: function () { + }, + activate: function () { } }; @@ -95,6 +93,8 @@ define([ on: function () { }, active: function () { + }, + activate: function () { } }, type = typeof obj.initActivation(arg); @@ -119,6 +119,8 @@ define([ }, active: function () { }, + activate: function () { + }, delegate: jasmine.createSpy() }; @@ -150,7 +152,7 @@ define([ return []; }); obj.onValidate(); - expect(obj.validate.calls.count()).toBe(3); + expect(obj.validate.calls.count()).toBe(1); }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js index 0923d84fce5ff..ce07b709467f2 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/abstract.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -43,17 +43,6 @@ define([ expect(model.validation).toEqual({}); }); }); - describe('initProperties method', function () { - it('check for chainable', function () { - expect(model.initProperties()).toEqual(model); - }); - it('check for extend', function () { - model.initProperties(); - expect(model.uid).toBeDefined(); - expect(model.noticeId).toBeDefined(); - expect(model.inputName).toBeDefined(); - }); - }); describe('setInitialValue method', function () { it('check for chainable', function () { expect(model.setInitialValue()).toEqual(model); @@ -78,15 +67,23 @@ define([ expect(model.additionalClasses).toEqual(1); }); it('check for empty additional class', function () { + var expectedResult = { + _required: model.required, + _warn: model.warn, + _error: model.error, + _disabled: model.disabled + }; + model.additionalClasses = ''; expect(model._setClasses()).toEqual(model); - expect(model.additionalClasses).toEqual(''); + expect(model.additionalClasses).toEqual(expectedResult); }); it('check for one class in additional', function () { var extendObject = { simple: true, - required: model.required, + _required: model.required, + _warn: model.warn, _error: model.error, _disabled: model.disabled }; @@ -98,7 +95,8 @@ define([ it('check for one class with spaces in additional', function () { var extendObject = { simple: true, - required: model.required, + _required: model.required, + _warn: model.warn, _error: model.error, _disabled: model.disabled }; @@ -111,7 +109,8 @@ define([ var extendObject = { simple: true, example: true, - required: model.required, + _required: model.required, + _warn: model.warn, _error: model.error, _disabled: model.disabled }; @@ -124,7 +123,8 @@ define([ var extendObject = { simple: true, example: true, - required: model.required, + _required: model.required, + _warn: model.warn, _error: model.error, _disabled: model.disabled }; @@ -139,10 +139,8 @@ define([ expect(model.getInitialValue()).toEqual(''); }); it('check with default value', function () { - var expected = 1; - - model.default = expected; - expect(model.getInitialValue()).toEqual(expected); + model.default = 1; + expect(model.getInitialValue()).toEqual(''); }); it('check with value', function () { var expected = 1; diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/boolean.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/boolean.test.js index a17a06ea55810..96814ce5ba23c 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/boolean.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/boolean.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date-time.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date-time.test.js new file mode 100644 index 0000000000000..9767ef81317fb --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date-time.test.js @@ -0,0 +1,41 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/*eslint max-nested-callbacks: 0*/ + +define([ + 'Magento_Ui/js/form/element/date', + 'mageUtils', + 'moment' +], function (DateElement, utils, moment) { + 'use strict'; + + describe('Magento_Ui/js/form/element/date', function () { + var params, model; + + beforeEach(function () { + params = { + dataScope: 'abstract', + options: { + showsTime: true + } + }; + model = new DateElement(params); + }); + + it('Check prepareDateTimeFormats function', function () { + spyOn(utils, 'convertToMomentFormat').and.callThrough(); + model.prepareDateTimeFormats(); + expect(utils.convertToMomentFormat).toHaveBeenCalled(); + }); + + it('Check onShiftedValueChange function', function () { + spyOn(moment, 'tz').and.callThrough(); + model.onShiftedValueChange('2016-12-23 9:11 PM'); + expect(moment.tz).toHaveBeenCalled(); + }); + + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js index 632fef3d841d1..a91a7d93089c6 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/date.test.js @@ -1,13 +1,14 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*eslint max-nested-callbacks: 0*/ define([ - 'Magento_Ui/js/form/element/date' -], function (DateElement) { + 'Magento_Ui/js/form/element/date', + 'mageUtils' +], function (DateElement, utils) { 'use strict'; describe('Magento_Ui/js/form/element/date', function () { @@ -20,32 +21,11 @@ define([ model = new DateElement(params); }); - describe('getInitialValue method', function () { - it('check for default', function () { - expect(model.getInitialValue()).toEqual(''); - }); - it('check with default value', function () { - model.default = 1; - expect(model.getInitialValue()).toEqual('01/01/1970'); - }); - it('check with value', function () { - model.value(1); - expect(model.getInitialValue()).toEqual('01/01/1970'); - }); - it('check with value and default', function () { - model.default = 1; - model.value(0); - expect(model.getInitialValue()).toEqual(0); - }); - }); - describe('initProperties method', function () { - it('check for chainable', function () { - expect(model.initProperties()).toEqual(model); - }); - it('check for extend', function () { - model.initProperties(); - expect(model.dateFormat).toBeDefined(); - }); + it('Check prepareDateTimeFormats function', function () { + spyOn(utils, 'convertToMomentFormat'); + model.prepareDateTimeFormats(); + expect(utils.convertToMomentFormat).toHaveBeenCalled(); }); + }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/file-uploader.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/file-uploader.test.js index b32c30a0127e9..64a31985360a2 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/file-uploader.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/file-uploader.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/multiselect.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/multiselect.test.js index 09f21f6b175ee..c0f4b345509d0 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/multiselect.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/multiselect.test.js @@ -1,46 +1,59 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -/*eslint max-nested-callbacks: 0*/ - +/* eslint max-nested-callbacks: 0 */ define([ - 'Magento_Ui/js/form/element/multiselect' -], function (MultiselectElement) { + 'squire' +], function (Squire) { 'use strict'; - describe('Magento_Ui/js/form/element/multiselect', function () { - var params, model; + var injector = new Squire(), + mocks = { + 'Magento_Ui/js/lib/core/events': { + on: jasmine.createSpy() + }, + 'Magento_Ui/js/lib/registry/registry': { + get: function() { + return { + get: jasmine.createSpy(), + set: jasmine.createSpy() + }; + }, + create: jasmine.createSpy(), + set: jasmine.createSpy(), + async: jasmine.createSpy() + }, + '/mage/utils/wrapper': jasmine.createSpy() + }, + obj, + dataScope = 'dataScope'; + + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Ui/js/form/element/multiselect'], function (Constr) { + obj = new Constr({ + provider: 'provName', + name: '', + index: '', + dataScope: dataScope + }); - beforeEach(function () { - params = { - dataScope: 'multiselect' - }; - model = new MultiselectElement(params); + done(); }); + }); - describe('getInitialValue method', function () { - it('check for default', function () { - expect(model.getInitialValue()).toEqual(undefined); - }); - it('check with default value', function () { - model.indexedOptions = { - Select: { - value: 'value' - } - }; - model.default = 'Select'; - expect(model.getInitialValue()).toEqual(['value']); + describe('Magento_Ui/js/form/element/multiselect', function () { + describe('"setPrepareToSendData" method', function () { + it('Check method call with empty array as parameter.', function () { + expect(obj.setPrepareToSendData([])).toBeUndefined(); + expect(obj.source.set).toHaveBeenCalledWith(dataScope + '-prepared-for-send', ''); }); - it('check with value', function () { - model.indexedOptions = { - Select: { - value: 'value' - } - }; - model.value('Select'); - expect(model.getInitialValue()).toEqual(['value']); + + it('Check method call with array with data as parameter.', function () { + expect(obj.setPrepareToSendData(['1', '2', '3'])).toBeUndefined(); + expect(obj.source.set).toHaveBeenCalledWith(dataScope + '-prepared-for-send', ['1', '2', '3']); }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/post-code.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/post-code.test.js index 77c71ff103665..61adf4a0d8374 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/post-code.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/post-code.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/region.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/region.test.js index fa61cfa780b3d..642bff4bf34fd 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/region.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/region.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js index 6ce3428a6cb35..13b764442108b 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/select.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -52,64 +52,6 @@ define([ it('check for chainable', function () { expect(model.initConfig({})).toEqual(model); }); - it('check with empty value and caption', function () { - var config = { - options: [{ - label: 'Caption', - value: null - }, { - label: 'Some label', - value: 'Some value' - }], - caption: 'Main caption' - }, - expected = { - options: [config.options[1]], - caption: config.caption - }; - - expect(model.initConfig(config)).toEqual(model); - expect(config).toEqual(expected); - }); - it('check with empty value', function () { - var config = { - options: [{ - label: 'Caption', - value: null - }, { - label: 'Some label', - value: 'Some value' - }] - }, - expected = { - options: [config.options[1]], - caption: config.options[0].label - }; - - expect(model.initConfig(config)).toEqual(model); - expect(config).toEqual(expected); - }); - it('check with multiple empty value', function () { - var config = { - options: [{ - label: 'Caption', - value: null - }, { - label: 'Some label', - value: 'Some value' - }, { - label: 'Another caption', - value: null - }] - }, - expected = { - options: [config.options[1]], - caption: config.options[0].label - }; - - expect(model.initConfig(config)).toEqual(model); - expect(config).toEqual(expected); - }); }); describe('initObservable method', function () { it('check for chainable', function () { @@ -179,7 +121,7 @@ define([ { value: 'valLast' }]; - model.caption = false; + model.caption(''); expect(model.normalizeData('')).toEqual('valFirst'); }); }); @@ -246,6 +188,39 @@ define([ expect(model.setVisible).toHaveBeenCalled(); expect(model.toggleInput).toHaveBeenCalled(); }); + it('Check call "parseOptions" method without predefined "captionValue" property', function () { + var data = [{ + value: null, + label: 'label' + }, { + value: 'value' + }]; + + model.options = jasmine.createSpy(); + model.caption = jasmine.createSpy().and.returnValue(false); + + model.setOptions(data); + expect(model.options).toHaveBeenCalledWith([{ + value: 'value' + }]); + expect(model.caption.calls.allArgs()).toEqual([[], ['label']]); + + }); + it('Check call "parseOptions" method with predefined "captionValue" property', function () { + var data = [{ + value: 'value', + label: 'label' + }]; + + model.options = jasmine.createSpy(); + model.caption = jasmine.createSpy().and.returnValue(false); + model.captionValue = 'value'; + + model.setOptions(data); + expect(model.options).toHaveBeenCalledWith([]); + expect(model.caption.calls.allArgs()).toEqual([[], ['label']]); + + }); }); describe('getPreview method', function () { it('check for default preview', function () { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/textarea.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/textarea.test.js index 608a2cd27d25e..c93769e5f9a1d 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/textarea.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/textarea.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js index 5a32d5c991e3e..3fb10ff2b401e 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/form.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -67,26 +67,26 @@ define([ expect(type).toEqual('object'); }); }); - describe('"initProperties" method', function () { + describe('"initConfig" method', function () { it('Check for defined ', function () { - expect(obj.hasOwnProperty('initProperties')).toBeDefined(); + expect(obj.hasOwnProperty('initConfig')).toBeDefined(); }); it('Check method type', function () { - var type = typeof obj.initProperties; + var type = typeof obj.initConfig; expect(type).toEqual('function'); }); it('Check returned value if method called without arguments', function () { - expect(obj.initProperties()).toBeDefined(); + expect(obj.initConfig()).toBeDefined(); }); it('Check returned value type if method called without arguments', function () { - var type = typeof obj.initProperties(); + var type = typeof obj.initConfig(); expect(type).toEqual('object'); }); - it('Check this.selector property (is modify in initProperties method)', function () { + it('Check this.selector property (is modify in initConfig method)', function () { obj.selector = null; - obj.initProperties(); + obj.initConfig(); expect(typeof obj.selector).toEqual('string'); }); }); @@ -117,33 +117,6 @@ define([ expect(type).toEqual('function'); }); - it('Check call method "this.validate" inner save method', function () { - obj.validate = jasmine.createSpy(); - obj.source.get = jasmine.createSpy().and.callFake(function () { - return true; - }); - obj.save(); - expect(obj.validate).toHaveBeenCalled(); - }); - it('Check call method "this.source.get" inner save method', function () { - obj.validate = jasmine.createSpy(); - obj.source.get = jasmine.createSpy().and.callFake(function () { - return true; - }); - obj.save(); - expect(obj.source.get).toHaveBeenCalled(); - }); - it('Check call method "this.submit" inner save method', function () { - obj.validate = jasmine.createSpy(); - obj.source.get = jasmine.createSpy().and.callFake(function () { - return false; - }); - obj.submit = jasmine.createSpy().and.callFake(function () { - return true; - }); - obj.save(); - expect(obj.source.get).toHaveBeenCalled(); - }); }); describe('"submit" method', function () { it('Check for defined ', function () { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/provider.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/provider.test.js index 3b112d0b43ebb..04e0abcb63b50 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/provider.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/provider.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js index 6a646c7c70909..0f987080f093c 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/ui-select.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -18,11 +18,13 @@ define([ describe('Magento_Ui/js/form/element/ui-select', function () { var obj = new Constr({ + name: 'uiSelect', dataScope: '', provider: 'provider' }); obj.value = ko.observableArray([]); + obj.cacheOptions.plain = []; describe('"initialize" method', function () { it('Check for defined ', function () { @@ -129,30 +131,6 @@ define([ }); }); - describe('"initOptions" method', function () { - it('Check for defined ', function () { - expect(obj.hasOwnProperty('initOptions')).toBeDefined(); - }); - it('Check answer type', function () { - var type = typeof obj.initOptions; - - expect(type).toEqual('function'); - }); - it('Check returned value if method called without arguments', function () { - expect(obj.initOptions()).toBeDefined(); - }); - it('Check returned value type if method called without arguments', function () { - var type = typeof obj.initOptions(); - - expect(type).toEqual('object'); - }); - it('Check "this.optionsConfig.options" property', function () { - obj.optionsConfig.options = null; - obj.initOptions(); - expect(obj.optionsConfig.options).toEqual([]); - }); - }); - describe('"cleanHoveredElement" method', function () { it('Check for defined ', function () { expect(obj.hasOwnProperty('cleanHoveredElement')).toBeDefined(); @@ -170,11 +148,6 @@ define([ expect(type).toEqual('object'); }); - it('Check changes "this.hoverElIndex" observe variable', function () { - obj.hoverElIndex(5); - obj.cleanHoveredElement(); - expect(obj.hoverElIndex()).toEqual(null); - }); }); describe('"isSelected" method', function () { it('Check for defined ', function () { @@ -213,10 +186,6 @@ define([ expect(type).toEqual('boolean'); }); - it('Must return false if "hoverElIndex" does not equal value', function () { - obj.hoverElIndex(1); - expect(obj.isHovered(2)).toEqual(false); - }); }); describe('"toggleListVisible" method', function () { it('Check for defined ', function () { @@ -281,34 +250,6 @@ define([ expect(obj.value()).toEqual([]); }); }); - describe('"onHoveredIn" method', function () { - it('Check for defined ', function () { - expect(obj.hasOwnProperty('onHoveredIn')).toBeDefined(); - }); - it('Check answer type', function () { - var type = typeof obj.onHoveredIn; - - expect(type).toEqual('function'); - }); - it('Observe variable "hoverElIndex" must have transmitted value', function () { - obj.onHoveredIn({}, 5); - expect(obj.hoverElIndex()).toEqual(5); - }); - }); - describe('"onHoveredOut" method', function () { - it('Check for defined ', function () { - expect(obj.hasOwnProperty('onHoveredOut')).toBeDefined(); - }); - it('Check answer type', function () { - var type = typeof obj.onHoveredOut; - - expect(type).toEqual('function'); - }); - it('Observe variable "hoverElIndex" must be null', function () { - obj.onHoveredOut(); - expect(obj.hoverElIndex()).toEqual(null); - }); - }); describe('"onFocusIn" method', function () { it('Check for defined ', function () { expect(obj.hasOwnProperty('onFocusIn')).toBeDefined(); @@ -319,7 +260,7 @@ define([ expect(type).toEqual('function'); }); it('Observe variable "multiselectFocus" must be true', function () { - obj.onFocusIn(); + obj.onFocusIn({}, {}); expect(obj.multiselectFocus()).toEqual(true); }); }); @@ -351,14 +292,6 @@ define([ obj.enterKeyHandler(); expect(obj.listVisible()).toEqual(true); }); - it('if list visible is true, method "toggleOptionSelected" must be called with argument', function () { - obj.listVisible(true); - obj.hoverElIndex(0); - obj.options(['magento']); - obj.toggleOptionSelected = jasmine.createSpy(); - obj.enterKeyHandler(); - expect(obj.toggleOptionSelected).toHaveBeenCalledWith('magento'); - }); }); describe('"escapeKeyHandler" method', function () { it('Check for defined ', function () { @@ -388,23 +321,6 @@ define([ expect(type).toEqual('function'); }); - it('If "hoverElIndex" is null - "hoverElIndex" must be 0', function () { - obj.hoverElIndex(null); - obj.pageDownKeyHandler(); - expect(obj.hoverElIndex()).toEqual(0); - }); - it('If "hoverElIndex" is number - "hoverElIndex" must be number + 1', function () { - obj.hoverElIndex(1); - obj.options(['one', 'two', 'three']); - obj.pageDownKeyHandler(); - expect(obj.hoverElIndex()).toEqual(2); - }); - it('If "hoverElIndex" is number and number === options length -1, "hoverElIndex" must be 0', function () { - obj.hoverElIndex(1); - obj.options(['one', 'two']); - obj.pageDownKeyHandler(); - expect(obj.hoverElIndex()).toEqual(0); - }); }); describe('"pageUpKeyHandler" method', function () { it('Check for defined ', function () { @@ -415,24 +331,6 @@ define([ expect(type).toEqual('function'); }); - it('If "hoverElIndex" is null - "hoverElIndex" must be option length -1', function () { - obj.hoverElIndex(null); - obj.options(['one', 'two']); - obj.pageUpKeyHandler(); - expect(obj.hoverElIndex()).toEqual(1); - }); - it('If "hoverElIndex" is 0 - "hoverElIndex" must be option length -1', function () { - obj.hoverElIndex(0); - obj.options(['one', 'two']); - obj.pageUpKeyHandler(); - expect(obj.hoverElIndex()).toEqual(1); - }); - it('If "hoverElIndex" is number - "hoverElIndex" must be number - 1', function () { - obj.hoverElIndex(2); - obj.options(['one', 'two']); - obj.pageUpKeyHandler(); - expect(obj.hoverElIndex()).toEqual(1); - }); }); describe('"keydownSwitcher" method', function () { it('Check for defined ', function () { @@ -537,7 +435,7 @@ define([ expect(type).toEqual('function'); }); it('Check returned value if selected', function () { - obj.cacheOptions = [{value: 'magento'}, {value: 'magento2'}]; + obj.cacheOptions.plain = [{value: 'magento'}, {value: 'magento2'}]; obj.value(['magento', 'magento2']); expect(obj.getSelected()).toEqual([{value: 'magento'}, {value: 'magento2'}]); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js index c282660342ad1..999d1f4a037d7 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/actions.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -82,19 +82,5 @@ define([ action.hidden = false; expect(model.isActionVisible(action)).toBeTruthy(); }); - - it('Check toggleList function', function () { - model.toggleList(0); - expect(model.opened()).toEqual(0); - model.toggleList(0); - expect(model.opened()).toBeFalsy(); - }); - - it('Check closeList function', function () { - model.toggleList(0); - expect(model.opened()).toEqual(0); - model.closeList(0); - expect(model.opened()).toBeFalsy(); - }); }); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js index b4db54bdb7b65..fa0148096add0 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/column.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*eslint max-nested-callbacks: 0*/ @@ -17,7 +17,8 @@ define([ sortable: true, sorting: false, headerTmpl: 'header', - bodyTmpl: 'body' + bodyTmpl: 'body', + source: function () {} }); }); @@ -27,11 +28,6 @@ define([ expect(column.sorting).toBe('asc'); }); - it('apply sorting in other direction', function () { - column.sort(true).sort(true); - expect(column.sorting).toBe('desc'); - }); - it('remove sorting', function () { column.sort(false); expect(column.sorting).toBeFalsy(); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js index e93209a5dfd04..7e82592d36de9 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/date.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*eslint max-nested-callbacks: 0*/ @@ -22,21 +22,14 @@ define([ }); }); - describe('initProperties method', function () { + describe('initConfig method', function () { it('check for chainable', function () { - expect(date.initProperties()).toEqual(date); + expect(date.initConfig()).toEqual(date); }); it('check for extend', function () { - date.initProperties(); + date.initConfig(); expect(date.dateFormat).toBeDefined(); }); }); - - describe('getLabel method', function () { - it('check format', function () { - date.dateFormat = dateFormat; - expect(date.getLabel(dateRaw)).toBe(dateFormatted); - }); - }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js index 194c9f4919c0c..2f522dce21f16 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/multiselect.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -142,4 +142,4 @@ define([ expect(multiSelect.selected()).toEqual([5, 6]); }); }); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js index 9b9e0b35cf3eb..ea134c86f5121 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/columns/select.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /*eslint max-nested-callbacks: 0*/ @@ -25,11 +25,6 @@ define([ it('get label while options empty', function () { expect(select.getLabel(2)).toBe(''); }); - - it('get label for existed value', function () { - select.options = opts; - expect(select.getLabel(2)).toBe('b'); - }); }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js deleted file mode 100644 index d85890b2c98f4..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/bookmarks.test.js +++ /dev/null @@ -1,104 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'Magento_Ui/js/grid/controls/bookmarks/bookmarks' -], function (Bookmarks) { - 'use strict'; - describe('ui/js/grid/controls/bookmarks/bookmarks', function () { - var bookmarksElement, returnContext; - - beforeEach(function () { - bookmarksElement = new Bookmarks({ - index: 'index', - name: 'name', - indexField: 'id', - dataScope: 'scope', - provider: 'provider' - }); - - }); - it('has initialize method', function () { - spyOn(bookmarksElement, "initialize"); - bookmarksElement.initialize(); - expect(bookmarksElement.initialize).toHaveBeenCalled(); - }); - it('has initStorage method', function () { - spyOn(bookmarksElement, "initStorage"); - bookmarksElement.initStorage(); - expect(bookmarksElement.initStorage).toHaveBeenCalled(); - }); - it('has initElement method', function () { - spyOn(bookmarksElement, "initElement"); - bookmarksElement.initElement(); - expect(bookmarksElement.initElement).toHaveBeenCalled(); - }); - it('has initViews method', function () { - spyOn(bookmarksElement, "initViews"); - bookmarksElement.initViews(); - expect(bookmarksElement.initViews).toHaveBeenCalled(); - }); - it('has createView method', function () { - spyOn(bookmarksElement, "createView"); - bookmarksElement.createView(); - expect(bookmarksElement.createView).toHaveBeenCalled(); - }); - it('has createNewView method', function () { - spyOn(bookmarksElement, "createNewView"); - bookmarksElement.createNewView(); - expect(bookmarksElement.createNewView).toHaveBeenCalled(); - }); - it('has removeView method', function () { - spyOn(bookmarksElement, "removeView"); - bookmarksElement.removeView(); - expect(bookmarksElement.removeView).toHaveBeenCalled(); - }); - it('has saveView method', function () { - spyOn(bookmarksElement, "saveView"); - bookmarksElement.saveView(); - expect(bookmarksElement.saveView).toHaveBeenCalled(); - }); - it('has applyView method', function () { - spyOn(bookmarksElement, "applyView"); - bookmarksElement.applyView(); - expect(bookmarksElement.applyView).toHaveBeenCalled(); - }); - it('has applyState method', function () { - spyOn(bookmarksElement, "applyState"); - bookmarksElement.applyState(); - expect(bookmarksElement.applyState).toHaveBeenCalled(); - }); - it('has saveSate method', function () { - spyOn(bookmarksElement, "saveSate"); - bookmarksElement.saveSate(); - expect(bookmarksElement.saveSate).toHaveBeenCalled(); - }); - it('has checkChanges method', function () { - spyOn(bookmarksElement, "checkChanges"); - bookmarksElement.checkChanges(); - expect(bookmarksElement.checkChanges).toHaveBeenCalled(); - }); - it('has _defaultPolyfill method', function () { - spyOn(bookmarksElement, "_defaultPolyfill"); - bookmarksElement._defaultPolyfill(); - expect(bookmarksElement._defaultPolyfill).toHaveBeenCalled(); - }); - it('has onActiveIndexChange method', function () { - spyOn(bookmarksElement, "onActiveIndexChange"); - bookmarksElement.onActiveIndexChange(); - expect(bookmarksElement.onActiveIndexChange).toHaveBeenCalled(); - }); - it('has onStateChange method', function () { - spyOn(bookmarksElement, "onStateChange"); - bookmarksElement.onStateChange(); - expect(bookmarksElement.onStateChange).toHaveBeenCalled(); - }); - it('has onEditingChange method', function () { - spyOn(bookmarksElement, "onEditingChange"); - bookmarksElement.onEditingChange(); - expect(bookmarksElement.onEditingChange).toHaveBeenCalled(); - }); - }); -}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js index 42eee106807b5..f9273089ce298 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/storage.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js deleted file mode 100644 index 791dccb14003c..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/bookmarks/view.test.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'Magento_Ui/js/grid/controls/bookmarks/view' -], function (BookmarkView) { - 'use strict'; - describe('ui/js/grid/controls/bookmarks/view', function () { - var view, returnContextOfItself; - beforeEach(function(){ - view = new BookmarkView({ - index: 'index', - name: 'name', - indexField: 'id', - dataScope: 'scope', - provider: 'provider' - }); - }); - it('has initialize method', function () { - spyOn(view, "initialize"); - view.initialize(); - expect(view.initialize).toHaveBeenCalled(); - }); - it('has initObservable method', function () { - spyOn(view, "initObservable"); - view.initObservable(); - expect(view.initObservable).toHaveBeenCalled(); - }); - it('has getData method', function () { - spyOn(view, "getData"); - view.getData(); - expect(view.getData).toHaveBeenCalled(); - }); - it('has setData method', function () { - spyOn(view, "setData"); - view.setData(); - expect(view.setData).toHaveBeenCalled(); - }); - it('has syncLabel method', function () { - spyOn(view, "syncLabel"); - view.syncLabel(); - expect(view.syncLabel).toHaveBeenCalled(); - }); - it('has startEdit method', function () { - spyOn(view, "startEdit"); - view.startEdit(); - expect(view.startEdit).toHaveBeenCalled(); - }); - it('has exportView method', function () { - spyOn(view, "exportView"); - view.exportView(); - expect(view.exportView).toHaveBeenCalled(); - }); - it('has onActivate method', function () { - spyOn(view, "onActivate"); - view.onActivate(); - expect(view.onActivate).toHaveBeenCalled(); - }); - it('has onActiveChange method', function () { - spyOn(view, "onActiveChange"); - view.onActiveChange(); - expect(view.onActiveChange).toHaveBeenCalled(); - }); - }) -}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js index 85bb3ae2bb5ba..8d88b0f2802d6 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/controls/columns.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/data-storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/data-storage.test.js new file mode 100644 index 0000000000000..b8f123dd59332 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/data-storage.test.js @@ -0,0 +1,76 @@ +/** + * Copyright © 2013-2017 Magento. All rights reserved. + * See COPYING.txt for license details. + */ + +/*eslint max-nested-callbacks: 0*/ +/*jscs:disable requireCamelCaseOrUpperCaseIdentifiers*/ +define([ + 'mageUtils', + 'Magento_Ui/js/grid/data-storage' +], function (utils, DataStorage) { + 'use strict'; + + describe('Magento_Ui/js/grid/data-storage', function () { + describe('costructor', function () { + it('converts dataScope property to array', function () { + var model = new DataStorage({ + dataScope: 'magento' + }); + + expect(model.dataScope).toEqual(['magento']); + }); + }); + + describe('hasScopeChanged', function () { + it('is function', function () { + var model = new DataStorage({ + dataScope: '' + }); + + expect(model.hasScopeChanged).toBeDefined(); + expect(typeof model.hasScopeChanged).toEqual('function'); + }); + + it('returns false if no requests have been made', function () { + var model = new DataStorage({ + dataScope: '' + }); + + expect(model.hasScopeChanged()).toBeFalsy(); + }); + + it('tells whether parameters defined in the dataScope property have changed', function () { + var params, newParams, model; + + params = { + namespace: 'magento', + search: '', + filters: { + store_id: 0 + }, + sorting: {}, + paging: {} + }; + + newParams = utils.extend({}, params, { + search: 'magento', + filters: { + store_id: 1 + } + }); + + model = new DataStorage({ + dataScope: 'filters.store_id' + }); + + model.cacheRequest({ + totalRecords: 0 + }, params); + + expect(model.hasScopeChanged(params)).toBeFalsy(); + expect(model.hasScopeChanged(newParams)).toBeTruthy(); + }); + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js index 094ad409e5eb4..f6809d9c22c23 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/editing/bulk.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -13,6 +13,7 @@ define([ beforeEach(function () { bulkObj = new Bulk(); + bulkObj.editor = jasmine.createSpy('editor'); }); it('has initObservable', function () { expect(bulkObj).toBeDefined(); @@ -33,5 +34,5 @@ define([ bulkObj.updateState(); expect(bulkObj.updateState).toHaveBeenCalled(); }); - }) -}); \ No newline at end of file + }); +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js index 0555f056f5e90..712506b4b7b47 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/filters.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -13,7 +13,9 @@ define([ temp; beforeEach(function () { - filterObj = new Filter(); + filterObj = new Filter({ + name: 'filter' + }); }); it('has been initialized', function () { expect(filterObj).toBeDefined(); @@ -39,16 +41,6 @@ define([ temp = filterObj.cancel(); expect(temp).toBeDefined(); }); - it('has isOpened method', function () { - filterObj.opened = function () { - return true; - }; - filterObj.hasVisible = function () { - return true; - }; - temp = filterObj.isOpened(); - expect(temp).toBeTruthy(); - }); it('has isFilterVisible method', function () { temp = { visible: function () { @@ -69,15 +61,5 @@ define([ filterObj.hasVisible(); expect(filterObj.hasVisible).toHaveBeenCalled(); }); - it('has extractActive method', function () { - spyOn(filterObj, 'extractActive'); - filterObj.extractActive(); - expect(filterObj.extractActive).toHaveBeenCalled(); - }); - it('has extractPreviews method', function () { - spyOn(filterObj, 'extractPreviews'); - filterObj.extractPreviews(); - expect(filterObj.extractPreviews).toHaveBeenCalled(); - }); }); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js index 44640d6ef2063..78c66acbb08b8 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/filters/range.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -28,18 +28,6 @@ define([ group.elems.push({id:1}, {id:1}); expect(group.elems()).not.toEqual([]); }); - it('Check for reset elements.', function () { - var elem = { - value: false, - reset: function() { - this.value = true; - } - }; - - group.elems.push(elem); - expect(group.reset()).toBe(group); - expect(group.elems.first().value).toBe(true); - }); it('Check for clear elements.', function () { var elem = { value: 'text', diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js index 36c2823eaf9e6..f2d0119472647 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/paging/paging.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -29,113 +29,22 @@ define([ it('normal + boundary values', function () { expect(paging.normalize(1)).toBe(1); - expect(paging.normalize(2)).toBe(2); - expect(paging.normalize(4)).toBe(4); }); it('out of boundary values', function () { expect(paging.normalize(0)).toBe(1); - expect(paging.normalize(5)).toBe(4); - }); - }); - - describe('countPages method', function () { - it('correct number of pages', function () { - paging.countPages(); - expect(paging.pages).toBe(4); - }); - - it('if no records', function () { - paging.totalRecords = 0; - paging.countPages(); - expect(paging.pages).toBe(1); - }); - }); - - describe('page manipualations', function () { - it('setPage method', function () { - paging.setPage(2); - expect(paging.current).toBe(2); - }); - - it('next', function () { - paging.current = 1; - paging.next(); - expect(paging.current).toBe(2); - }); - - it('next out of boundary', function () { - paging.current = 4; - paging.next(); - expect(paging.current).toBe(4); - }); - - it('prev', function () { - paging.current = 4; - paging.prev(); - expect(paging.current).toBe(3); - }); - - it('prev out of boundary', function () { - paging.current = 1; - paging.prev(); - expect(paging.current).toBe(1); - }); - - it('goFirst', function () { - paging.goFirst(); - expect(paging.current).toBe(1); - }); - - it('goLast', function () { - paging.goLast(); - expect(paging.current).toBe(4); - }); - - it('isFirst for 1st page', function () { - paging.current = 1; - expect(paging.isFirst()).toBeTruthy(); - }); - - it('isFirst for 2nd page', function () { - paging.current = 2; - expect(paging.isFirst()).toBeFalsy(); - }); - - it('isLast for last page', function () { - paging.current = 4; - expect(paging.isLast()).toBeTruthy(); - }); - - it('isLast for first page', function () { - paging.current = 1; - expect(paging.isLast()).toBeFalsy(); - }); - }); - - describe('countPages method', function () { - it('correct number of pages', function () { - paging.countPages(); - expect(paging.pages).toBe(4); - }); - - it('if no records', function () { - paging.totalRecords = 0; - paging.countPages(); - expect(paging.pages).toBe(1); }); }); describe('onPagesChange method', function () { - it('pages amount became less than current', function () { - paging.current = 4; - expect(paging.current).toBe(4); - paging.onPagesChange(2); - expect(paging.current).toBe(2); + it('Check call "onPagesChange" method', function () { + paging.updateCursor = jasmine.createSpy(); + paging.onPagesChange(); + expect(paging.updateCursor).toHaveBeenCalled(); }); }); - describe('ititObservable method', function () { + describe('initObservable method', function () { it('_current will be defined', function () { expect(paging._current).toBeDefined(); }); @@ -144,14 +53,6 @@ define([ paging.current = 2; expect(paging._current()).toBe(2); }); - - it('write into current', function () { - spyOn(paging, 'normalize').and.callThrough(); - spyOn(paging._current, 'notifySubscribers'); - paging._current(4); - expect(paging.current).toBe(4); - expect(paging._current.notifySubscribers).toHaveBeenCalledWith(4); - }); }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js index 948bfb84a85da..07a38e4ad5d13 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/resize.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -63,10 +63,10 @@ define([ index: 1, column: data, on: function (arg1, arg2) {} - } + }; }); spyOn(ko, 'contextFor').and.callFake(function () { - return {$index: 1, $parent: obj} + return {$index: 1, $parent: obj}; }); $._data = jasmine.createSpy().and.callFake(function () { return { @@ -82,45 +82,6 @@ define([ type = typeof obj.initColumn; expect(type).toEqual('function'); }); - it('Check call "this.getDefaultWidth" method', function () { - spyOn(obj, 'getDefaultWidth'); - obj.initColumn('magento'); - expect(obj.getDefaultWidth).toHaveBeenCalledWith('magento'); - }); - it('Check call "this.hasColumn" method', function () { - spyOn(obj, 'hasColumn').and.callFake(function () { - return false; - }); - obj.initColumn('magento'); - expect(obj.hasColumn).toHaveBeenCalled(); - }); - it('Check call "this.initResizableElement" method', function () { - spyOn(obj, 'hasColumn').and.callFake(function () { - return false; - }); - spyOn(obj, 'initResizableElement').and.callFake(function (arg) { - return true; - }); - obj.initColumn('magento'); - expect(obj.initResizableElement).toHaveBeenCalled(); - }); - it('Check call "this.setStopPropagationHandler" method', function () { - spyOn(obj, 'hasColumn').and.callFake(function () { - return false; - }); - spyOn(obj, 'setStopPropagationHandler').and.callFake(function (arg) { - return true; - }); - obj.initColumn('magento'); - expect(obj.setStopPropagationHandler).toHaveBeenCalledWith('magento'); - }); - it('Check call "this.refreshLastColumn" method', function () { - spyOn(obj, 'refreshLastColumn').and.callFake(function (arg) { - return true; - }); - obj.initColumn('magento'); - expect(obj.refreshLastColumn).toHaveBeenCalledWith('magento'); - }); }); describe('"initResizableElement" method', function () { beforeEach(function(){ @@ -194,9 +155,9 @@ define([ } }); spyOn(ko, 'contextFor').and.callFake(function () { - return {$index: ko.observable(1), $parent: obj} + return {$index: ko.observable(1), $parent: obj}; }); - spyOn(obj, 'getNextElement').and.callFake(function () { + spyOn(obj, 'getNextElements').and.callFake(function () { return true; }); event = {stopImmediatePropagation: function(){}} @@ -215,9 +176,9 @@ define([ obj.mousedownHandler(event); expect(obj.hasColumn).toHaveBeenCalled(); }); - it('Check call "this.getNextElement" method', function () { + it('Check call "this.getNextElements" method', function () { obj.mousedownHandler(event); - expect(obj.getNextElement).toHaveBeenCalled(); + expect(obj.getNextElements).toHaveBeenCalled(); }); }); describe('"mousemoveHandler" method', function () { @@ -261,7 +222,7 @@ define([ expect(obj.storageColumnsData[2]).toEqual(200); }); }); - describe('"getNextElement" method', function () { + describe('"getNextElements" method', function () { beforeEach(function(){ spyOn(ko, 'dataFor').and.callFake(function (data) { return { @@ -275,24 +236,24 @@ define([ }); }); it('Check for defined ', function () { - expect(obj.hasOwnProperty('getNextElement')).toBeDefined(); + expect(obj.hasOwnProperty('getNextElements')).toBeDefined(); }); it('Check method type', function () { - type = typeof obj.getNextElement; + type = typeof obj.getNextElements; expect(type).toEqual('function'); }); it('Check call "this.hasColumn" method', function () { spyOn(obj, 'hasColumn').and.callFake(function () { return 'magento'; }); - obj.getNextElement('magento'); + obj.getNextElements('magento'); expect(obj.hasColumn).toHaveBeenCalled(); }); it('Check returned value', function () { spyOn(obj, 'hasColumn').and.callFake(function () { return 'magento'; }); - expect(obj.getNextElement('magento')).toEqual('magento'); + expect(obj.getNextElements('magento')).toEqual('magento'); }); }); describe('"getDefaultWidth" method', function () { @@ -337,21 +298,11 @@ define([ arg = { index: 'magento' }; expect(typeof obj.hasColumn(arg, false)).toEqual('boolean'); }); - it('Must return false if object columnsElements has not model.index property', function () { - arg = { index: 'magento' }; - obj.columnsElements = {}; - expect(obj.hasColumn(arg, false)).toEqual(false); - }); it('Must return true if object columnsElements has model.index property', function () { arg = { index: 'magento' }; obj.columnsElements = {magento: 'magentoProp'}; expect(obj.hasColumn(arg, false)).toEqual(true); }); - it('Must return property if object columnsElements has property and second argument is true', function () { - arg = { index: 'magento' }; - obj.columnsElements = {magento: 'magentoProp'}; - expect(obj.hasColumn(arg, true)).toEqual('magentoProp'); - }); }); describe('"hasRow" method', function () { it('Check for defined ', function () { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js index b407fe3bebeae..8977d804c7c24 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -7,7 +7,7 @@ define([ ], function (Search) { 'use strict'; - describe('Magento_Ui/js/search/search', function () { + describe('Magento_Ui/js/grid/search/search', function () { var searchObj, temp; @@ -31,23 +31,6 @@ define([ searchObj.initChips(); expect(searchObj.chips).toHaveBeenCalled(); }); - it('has clear', function () { - spyOn(searchObj, 'value'); - searchObj.clear(); - expect(searchObj.value).toHaveBeenCalled(); - }); - it('has clear', function () { - spyOn(searchObj, 'inputValue'); - searchObj.cancel(); - expect(searchObj.inputValue).toHaveBeenCalled(); - }); - it('has apply', function () { - spyOn(searchObj, 'value'); - spyOn(searchObj, 'inputValue'); - searchObj.apply(); - expect(searchObj.value).toHaveBeenCalled(); - expect(searchObj.inputValue).toHaveBeenCalled(); - }); it('has updatePreview', function () { spyOn(searchObj, 'updatePreview'); searchObj.updatePreview(); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js index 4c2b68d8fcd01..8fce94fb61efe 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/sticky/sticky.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -135,10 +135,13 @@ define([ stickyObj.resetToTop(); expect(stickyObj.resetToTop).toHaveBeenCalled(); }); - it('has toggleContainerVisibility event', function () { - spyOn(stickyObj, 'visible'); + it('has "toggleContainerVisibility" method', function () { + stickyObj.visible = false; stickyObj.toggleContainerVisibility(); - expect(stickyObj.visible).toHaveBeenCalled(); + expect(stickyObj.visible).toEqual(true); + stickyObj.visible = true; + stickyObj.toggleContainerVisibility(); + expect(stickyObj.visible).toEqual(false); }); it('has adjustContainerElemsWidth event', function () { stickyObj.resizeContainer = function(){ @@ -156,17 +159,6 @@ define([ stickyObj.adjustOffset(); expect(stickyObj.adjustOffset).toHaveBeenCalled(); }); - it('has checkPos event', function () { - stickyObj.visible = function(){ - return false; - }; - stickyObj.getMustBeSticky = function(){ - return false; - }; - - data = stickyObj.checkPos(); - expect(data).toBeDefined(); - }) }); }) -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/tree-massactions.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/tree-massactions.test.js index 299fdc1b22d6a..f00524355f86a 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/tree-massactions.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/tree-massactions.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js deleted file mode 100644 index 9a0e8c2c4de08..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/core.test.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'Magento_Ui/js/lib/component/core' -], function (core) { - 'use strict'; - - describe('Magento_Ui/js/lib/component/core', function () { - var coreObj, - returnedValue; - - beforeEach(function () { - coreObj = core; - }); - it('has initialize', function () { - spyOn(coreObj, 'initialize'); - coreObj.initialize(); - expect(coreObj.initialize).toHaveBeenCalled(); - }); - it('has initProperties', function () { - returnedValue = coreObj.initProperties(); - expect(typeof returnedValue).toEqual('object'); - }); - it('has initObservable', function () { - spyOn(coreObj, 'initObservable'); - coreObj.initObservable(); - expect(coreObj.initObservable).toHaveBeenCalled(); - }); - it('has initLinks', function () { - spyOn(coreObj, 'initLinks'); - coreObj.initLinks(); - expect(coreObj.initLinks).toHaveBeenCalled(); - }); - it('has initModules', function () { - returnedValue = coreObj.initModules(); - expect(typeof returnedValue).toEqual('object'); - }); - it('has initUnique', function () { - returnedValue = coreObj.initUnique(); - expect(typeof returnedValue).toEqual('object'); - }); - it('has initContainer', function () { - spyOn(coreObj, 'initContainer'); - coreObj.initContainer(); - expect(coreObj.initContainer).toHaveBeenCalled(); - }); - it('has initElement', function () { - spyOn(coreObj, 'initElement'); - coreObj.initElement(); - expect(coreObj.initElement).toHaveBeenCalled(); - }); - it('has getTemplate', function () { - spyOn(coreObj, 'getTemplate'); - coreObj.getTemplate(); - expect(coreObj.getTemplate).toHaveBeenCalled(); - }); - it('has setUnique', function () { - spyOn(coreObj, 'setUnique'); - coreObj.setUnique(); - expect(coreObj.setUnique).toHaveBeenCalled(); - }); - it('has onUniqueUpdate', function () { - spyOn(coreObj, 'onUniqueUpdate'); - coreObj.onUniqueUpdate(); - expect(coreObj.onUniqueUpdate).toHaveBeenCalled(); - }); - }); -}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js index cf122dbc31fdf..0459456ec5455 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/links.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ @@ -19,9 +19,6 @@ define([ }; }); - it('has defaults', function () { - expect(typeof linksObj.defaults).toEqual('object'); - }); it('has setLinks method', function () { returnedValue = linksObj.setLinks(undefined, 'imports'); expect(typeof returnedValue).toEqual('object'); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js deleted file mode 100644 index 51c460ab648ad..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/manip.test.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -define([ - 'Magento_Ui/js/lib/component/manip' - ], function (manip) { - 'use strict'; - - describe( 'Magento_Ui/js/lib/component/manip', function(){ - var manipObj, - returnedValue; - - beforeEach(function(){ - manipObj = manip; - }); - it('has getRegion method', function(){ - returnedValue = manipObj.getRegion("region"); - expect(returnedValue).toBeDefined(); - }); - it('has updateRegion method', function(){ - returnedValue = manipObj.updateRegion([],"region"); - expect(typeof returnedValue).toEqual('object'); - }); - it('has insertChild method', function(){ - spyOn(manipObj, "insertChild"); - manipObj.insertChild(); - expect(manipObj.insertChild).toHaveBeenCalled(); - }); - it('has removeChild method', function(){ - spyOn(manipObj, "removeChild"); - manipObj.removeChild(); - expect(manipObj.removeChild).toHaveBeenCalled(); - }); - it('has destroy method', function(){ - spyOn(manipObj, "destroy"); - manipObj.destroy(); - expect(manipObj.destroy).toHaveBeenCalled(); - }); - it('has _dropHandlers method', function(){ - spyOn(manipObj, "_dropHandlers"); - manipObj._dropHandlers(); - expect(manipObj._dropHandlers).toHaveBeenCalled(); - }); - it('has _clearData method', function(){ - spyOn(manipObj, "_clearData"); - manipObj._clearData(); - expect(manipObj._clearData).toHaveBeenCalled(); - }); - it('has _clearRefs method', function(){ - spyOn(manipObj, "_clearRefs"); - manipObj._clearRefs(); - expect(manipObj._clearRefs).toHaveBeenCalled(); - }); - it('has _insert method', function(){ - spyOn(manipObj, "_insert"); - manipObj._insert(); - expect(manipObj._insert).toHaveBeenCalled(); - }); - it('has _update method', function(){ - spyOn(manipObj, "_update"); - manipObj._update(); - expect(manipObj._update).toHaveBeenCalled(); - }); - - }); - }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js deleted file mode 100644 index 47e531677abef..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/provider.test.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -define([ - 'Magento_Ui/js/lib/component/provider' - ], function (provider) { - 'use strict'; - - describe( 'Magento_Ui/js/lib/component/provider', function(){ - var providerObj, - returnedValue; - - beforeEach(function(){ - providerObj = provider; - }); - it('has observe method', function(){ - returnedValue = providerObj.observe("elems"); - expect(typeof returnedValue).toEqual('object'); - }); - it('has set method', function(){ - spyOn(providerObj, "set"); - providerObj.set(); - expect(providerObj.set).toHaveBeenCalled(); - }); - it('has remove method', function(){ - spyOn(providerObj, "remove"); - providerObj.remove(); - expect(providerObj.remove).toHaveBeenCalled(); - }); - it('has restore method', function(){ - spyOn(providerObj, "restore"); - providerObj.restore(); - expect(providerObj.restore).toHaveBeenCalled(); - }); - it('has removeStored method', function(){ - spyOn(providerObj, "removeStored"); - providerObj.removeStored(); - expect(providerObj.removeStored).toHaveBeenCalled(); - }); - }); - }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js deleted file mode 100644 index c6b6784475f3b..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/component/traversal.test.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -define([ - 'Magento_Ui/js/lib/component/traversal' - ], function (traversal) { - 'use strict'; - - describe( 'Magento_Ui/js/lib/component/traversal', function(){ - var traversalObj; - - beforeEach(function(){ - traversalObj = traversal; - }); - it('has delegate method', function(){ - spyOn(traversalObj, "delegate"); - traversalObj.delegate(); - expect(traversalObj.delegate).toHaveBeenCalled(); - }); - }); - }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/events.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/events.test.js index a2a98975a1243..c9011e374ed43 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/events.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/events.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js index a8c06b7b34cc0..35f1adb72f2e3 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/datepicker.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -7,21 +7,34 @@ define([ 'ko', 'jquery', 'moment', + 'mageUtils', 'Magento_Ui/js/lib/knockout/bindings/datepicker' -], function (ko, $, moment) { +], function (ko, $, moment, utils) { 'use strict'; describe('Datepicker binding', function () { var observable, - element; + element, + config; beforeEach(function () { - element = $(''); + element = $(''); observable = ko.observable(); + config = { + options: { + dateFormat: 'M/d/yy', + storeLocale: 'en_US', + timeFormat: 'h:mm: a' + }, + storage: observable + }; + $(document.body).append(element); - ko.applyBindingsToNode(element[0], { datepicker: observable }); + ko.applyBindingsToNode(element[0], { + datepicker: config + }); }); afterEach(function () { @@ -29,24 +42,16 @@ define([ }); it('writes picked date\'s value to assigned observable', function () { - var openBtn, - todayBtn, - todayDate, - dateFormat, - result; - - dateFormat = element.datepicker('option', 'dateFormat'); - todayDate = moment().format(dateFormat); - - openBtn = $('img.ui-datepicker-trigger'); - todayBtn = $('[data-handler="today"]'); + var todayDate, momentFormat, result, + inputFormat = 'M/d/yy'; - openBtn.click(); - todayBtn.click(); + momentFormat = utils.convertToMomentFormat(inputFormat); + todayDate = moment().format(momentFormat); - result = moment(observable()).format(dateFormat); + element.datepicker('setTimezoneDate').blur().trigger('change'); + result = moment(observable()).format(momentFormat); expect(todayDate).toEqual(result); }); }); -}); \ No newline at end of file +}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js index 8d0a99361ea54..572b08e3a2b42 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/ko/bind/i18n.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -82,36 +82,5 @@ define([ expect(elWithVariable.attr(dataTranslateAttrName)) .toEqual(dataTranslateAttr.replace(/\$/g, variableText).replace(/\&/g, variableText)); }); - - it('if inline translation is on, ' + - 'and there is translation for this text,' + - ' set translated text for element', function () { - turnOnInlineTranslation(); - $.mage.translate.add(staticText, staticTextTranslatedRaw); - $.mage.translate.add(variableText, variableTranslatedRaw); - spyOn($.mage.translate, 'parsedTranslate').and.callThrough(); - - context.config.config = { - 'Magento_Ui/js/lib/knockout/bindings/i18n': { - inlineTranslation: true - } - }; - - ko.applyBindingsToNode(elWithStaticText[0], { - i18n: staticText - }); - ko.applyBindingsToNode(elWithVariable[0], { - i18n: variable - }); - - expect($.mage.translate.parsedTranslate).toHaveBeenCalledWith(staticText); - expect($.mage.translate.parsedTranslate).toHaveBeenCalledWith(variableText); - expect(elWithStaticText.text()).toEqual(staticTextTranslated); - expect(elWithVariable.text()).toEqual(variableTranslated); - expect(elWithStaticText.attr(dataTranslateAttrName)) - .toEqual(dataTranslateAttr.replace(/\$/g, staticText).replace(/\&/g, staticTextTranslated)); - expect(elWithVariable.attr(dataTranslateAttrName)) - .toEqual(dataTranslateAttr.replace(/\$/g, variableText).replace(/\&/g, variableTranslated)); - }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js deleted file mode 100644 index b6f9c42086040..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/events.test.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - - -define([ - 'Magento_Ui/js/lib/registry/events' -], function (EventBus) { - 'use strict'; - - describe('Magento_Ui/js/lib/registry/events', function () { - var storage = { - has : function(){ - return false; - }, - get : function(){ - return []; - } - }, - eventsClass = new EventBus(storage); - - describe('"resolve" method', function () { - it('Check for defined ', function () { - expect(eventsClass.resolve()).toBeDefined(); - }); - it('Check answer type', function () { - var type = typeof(eventsClass.resolve()); - - expect(type).toEqual('object'); - }); - }); - describe('"wait" method', function () { - it('Check for defined ', function () { - expect(eventsClass.wait([],{})).toBeDefined(); - }); - it('Check return object property "requests" defined', function () { - var thisObject = eventsClass.wait([],{}).requests; - - expect(thisObject).toBeDefined(); - }); - it('Check return object property "requests" type', function () { - var thisObject = typeof(eventsClass.wait([],{}).requests); - - expect(thisObject).toEqual('object'); - }); - }); - describe('"_resolve" method', function () { - it('Check completion method', function () { - eventsClass.request = [{ - callback: function(){return true;}, - deps: {} - }]; - expect(eventsClass._resolve(0)).toEqual(false); - }); - }); - }); -}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js index fd814d0a68fd4..249aad292cdd9 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/registry.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -38,13 +38,6 @@ define([ expect(type).toEqual('object'); }); - it('Check assigned value after used method', function () { - var elem = 'test', - prop = 'magento'; - - registry.set(elem, prop); - expect(registry.storage.data.get(elem)).toEqual(prop); - }); }); describe('"registry.get" method', function () { it('Check for defined', function () { @@ -63,14 +56,6 @@ define([ expect(type).toBeFalsy(); }); - it('Check called callback with arguments', function () { - var elems = ['magento'], - callback = function () {}; - - registry.events.wait = jasmine.createSpy(); - registry.get(elems, callback); - expect(registry.events.wait).toHaveBeenCalledWith(elems, callback); - }); }); describe('"registry.remove" method', function () { it('Check for defined', function () { @@ -89,13 +74,6 @@ define([ expect(type).toEqual('object'); }); - it('Check called registry.storage.remove with arguments', function () { - var elems = ['magento']; - - registry.storage.remove = jasmine.createSpy(); - registry.remove(elems); - expect(registry.storage.remove).toHaveBeenCalledWith(elems); - }); }); describe('"registry.has" method', function () { it('Check for defined', function () { @@ -106,24 +84,11 @@ define([ expect(type).toEqual('function'); }); - it('Check returned value if registry.storage has property', function () { - var name = 'magento'; - - registry.storage.data.set(name, 'magentoValue'); - expect(registry.has(name)).toEqual(true); - }); it('Check returned value if registry.storage has not property', function () { var name = 'magentoNonProperty'; expect(registry.has(name)).toEqual(false); }); - it('Check called registry.storage.has with arguments', function () { - var elems = ['magento']; - - registry.storage.has = jasmine.createSpy(); - registry.has(elems); - expect(registry.storage.has).toHaveBeenCalledWith(elems); - }); }); describe('"registry.async" method', function () { it('Check for defined', function () { @@ -149,22 +114,6 @@ define([ expect(type).toEqual('object'); }); - it('Check registry.storage for defined', function () { - registry.create(); - expect(registry.storage).toBeDefined(); - }); - it('Check registry.storage type', function () { - registry.create(); - expect(typeof registry.storage).toEqual('object'); - }); - it('Check registry.events for defined', function () { - registry.create(); - expect(registry.events).toBeDefined(); - }); - it('Check registry.events type', function () { - registry.create(); - expect(typeof registry.events).toEqual('object'); - }); }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js deleted file mode 100644 index a2e2fd3c1206b..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/lib/registry/storage.test.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ - -/*eslint max-nested-callbacks: 0*/ - -define([ - 'Magento_Ui/js/lib/registry/storage' -], function (Storage) { - 'use strict'; - - describe('Magento_Ui/js/lib/registry/storage', function () { - var storage = new Storage(); - describe('"Storage constructor"', function () { - it('Check for defined', function () { - expect(storage).toBeDefined(); - }); - it('Check type', function () { - var type = typeof storage; - - expect(type).toEqual('object'); - }); - it('Check storage.data for defined', function () { - var data = storage.data; - - expect(typeof data).toEqual('object'); - }); - }); - describe('"storage.get" method', function () { - it('Check for defined', function () { - expect(storage.hasOwnProperty('get')).toBeDefined(); - }); - it('Check type', function () { - var type = typeof storage.get; - - expect(type).toEqual('function'); - }); - it('Check returned value if argument is array values', function () { - var elem = 'magento', - value = 'magentoValue'; - - storage.data.set(elem, value); - expect(storage.get([elem])).toEqual([value]); - }); - it('Check returned value if called withot arguments', function () { - expect(storage.get()).toEqual([]); - }); - }); - describe('"storage.set" method', function () { - it('Check for defined', function () { - expect(storage.hasOwnProperty('set')).toBeDefined(); - }); - it('Check type', function () { - var type = typeof storage.set; - - expect(type).toEqual('function'); - }); - it('Check returned value for defined', function () { - expect(storage.set()).toBeDefined(); - }); - it('Check returned value type', function () { - var type = typeof storage.set(); - - expect(type).toEqual('object'); - }); - it('Check returned value if argument is "elem, value" ', function () { - var elem = 'magento', - value = 'magentoValue'; - - storage.set(elem, value); - expect(storage.data.get(elem)).toEqual(value); - }); - }); - describe('"storage.remove" method', function () { - it('Check for defined', function () { - expect(storage.hasOwnProperty('remove')).toBeDefined(); - }); - it('Check type', function () { - var type = typeof storage.remove; - - expect(type).toEqual('function'); - }); - it('Check returned value for defined', function () { - expect(storage.remove([])).toBeDefined(); - }); - it('Check returned value type', function () { - var type = typeof storage.remove([]); - - expect(type).toEqual('object'); - }); - it('Check if called with argument "elem" ', function () { - var elem = 'magento', - value = 'magentoValue'; - - storage.data.set(elem, value); - storage.remove([elem]); - expect(storage.data.get(elem)).not.toBeDefined(); - }); - }); - describe('"storage.has" method', function () { - it('Check for defined', function () { - expect(storage.hasOwnProperty('has')).toBeDefined(); - }); - it('Check type', function () { - var type = typeof storage.has; - - expect(type).toEqual('function'); - }); - it('Check returned value if data has element property', function () { - var elem = 'magento', - value = 'magentoValue'; - - storage.data.set(elem, value); - expect(storage.has([elem])).toEqual(true); - }); - it('Check returned value if data has not element property', function () { - expect(storage.has(['value'])).toEqual(false); - }); - }); - }); -}); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/alert.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/alert.test.js index 8dd704917fc4d..415b50865ed61 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/alert.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/alert.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/confirm.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/confirm.test.js index 24d953205927f..32c5f97c75bbd 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/confirm.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/confirm.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/modal.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/modal.test.js index 68e8ae79d43e6..412a3676c2e14 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/modal.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/modal.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/prompt.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/prompt.test.js index 7de07fde4712c..138e20bf9efc5 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/prompt.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/modal/prompt.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/lib/mage/apply.test.js b/dev/tests/js/jasmine/tests/lib/mage/apply.test.js index d460acba690ce..2742b7218bfd7 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/apply.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/apply.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/tests/lib/mage/gallery.test.js b/dev/tests/js/jasmine/tests/lib/mage/gallery.test.js deleted file mode 100644 index 984bdf0cc3919..0000000000000 --- a/dev/tests/js/jasmine/tests/lib/mage/gallery.test.js +++ /dev/null @@ -1,154 +0,0 @@ -/** - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. - */ -define([ - 'jquery', - 'text!tests/assets/gallery/config.json', - 'mage/gallery/gallery', - 'magnifier/magnify' -], function ($, config, gallery, magnifier) { - - 'use strict'; - - var body = $('body'), - galleryAPI, - conf = JSON.parse(config), - gallerySelector = '[data-gallery-role="gallery"]', - magnifierSelector = '[data-gallery-role="magnifier"]', - stageSelector = '[data-gallery-role="stage-shaft"]', - navSelector = '[data-gallery-role="nav-frame"]', - dotSelector = '[data-nav-type="dot"]', - navWrap = '[data-gallery-role="nav-wrap"]', - dataToUpdate = [ - { - img: 'data:image/png;base64,' + - 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII=' - }, { - img: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAw' + - 'CAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII=' - }, { - img: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAw' + - 'CAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII=' - }, { - img: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAw' + - 'CAAAAC0lEQVR42mP4Xw8AAoABf5/NhYYAAAAASUVORK5CYII=' - } - ], - waitsFor = function (test, fn) { - if (test()) { - fn(); - } else { - setTimeout(function () { - waitsFor(test, fn); - }, 10); - } - }; - - gallery(magnifier(conf, body), body); - - beforeEach(function () { - galleryAPI = $(gallerySelector).data('gallery'); - }); - - describe('magnifier/magnify', function () { - - if ('ontouchstart' in document.documentElement) { - it('magnifier is not initialized on mobile platforms', function () { - expect($(magnifierSelector).length).toBe(0); - }); - } else { - it('magnifier is defined', function () { - expect($(gallerySelector).magnify).toBeDefined(); - expect(typeof $(gallerySelector).magnify).toBe('function'); - expect($(magnifierSelector).hasClass('hidden')).toBeTruthy(); - }); - - it('magnifier is initialized on desktop platforms', function () { - expect($(magnifierSelector + ' img').attr('src')).toBe($(stageSelector + ' img').attr('src')); - }); - it('magnifier appearing on event on desktop platforms', function () { - var ev = conf.magnifierOpts.eventType === 'click' ? 'click' : 'mouseover'; - expect($($(magnifierSelector).children()[0]).hasClass('magnifier-large hidden')).toBeTruthy(); - $(stageSelector + ' img').trigger(ev); - expect($($(magnifierSelector).children()[0]).hasClass('magnifier-large hidden')).toBeFalsy(); - $(stageSelector + ' img').trigger('mouseleave'); - }); - } - }); - - describe('mage/gallery/gallery', function () { - - it('gallery loaded', function () { - expect($(navSelector).length).toBe(conf.data.length); - }); - - it('show last', function () { - galleryAPI.last(); - expect($(navSelector + ':eq(' + (conf.data.length - 1) + ')') - .attr('data-active') === 'true').toBeTruthy(); - }); - - it('show first', function () { - galleryAPI.first(); - expect($(navSelector + ':eq(0)').attr('data-active') === 'true').toBeTruthy(); - }); - - it('show next', function () { - galleryAPI.next(); - expect($(navSelector + ':eq(1)').attr('data-active') === 'true').toBeTruthy(); - }); - - it('show previous', function () { - galleryAPI.prev(); - expect($(navSelector + ':eq(0)').attr('data-active') === 'true').toBeTruthy(); - }); - - it('show by number', function () { - galleryAPI.seek(3); - expect($(navSelector + ':eq(2)').attr('data-active') === 'true').toBeTruthy(); - }); - - it('update options', function () { - expect($(navSelector).attr('data-nav-type') === 'thumb').toBeTruthy(); - galleryAPI.updateOptions({ - nav: 'dots' - }); - expect($(dotSelector).length).toBe(conf.data.length); - }); - - it('update data', function () { - galleryAPI.updateData(dataToUpdate); - expect($(dotSelector).length).toBe(dataToUpdate.length); - }); - - it('breakpoints override configs', function () { - expect($('.fotorama__arr').css('display')).toBe('block'); - }); - - it('fullscreen enter', function (done) { - expect($(navWrap).css('display') === 'block').toBeTruthy(); - galleryAPI.fotorama.requestFullScreen(); - - waitsFor(function () { - return $(navWrap).css('display') !== 'block'; - }, function () { - expect($(navWrap).css('display') === 'none').toBeTruthy(); - done(); - }); - }); - - it('fullscreen exit', function (done) { - expect($(navWrap).css('display') === 'none').toBeTruthy(); - galleryAPI.fotorama.cancelFullScreen(); - - waitsFor(function () { - return $(navWrap).css('display') !== 'none'; - }, function () { - expect($(navWrap).css('display') === 'block').toBeTruthy(); - done(); - }); - }); - - }); -}); diff --git a/dev/tests/js/jasmine/tests/lib/mage/misc.test.js b/dev/tests/js/jasmine/tests/lib/mage/misc.test.js new file mode 100644 index 0000000000000..170177b42ccb0 --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/misc.test.js @@ -0,0 +1,650 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'mageUtils', + 'moment' +], function (utils, moment) { + 'use strict'; + + describe('mageUtils', function () { + + it('Check convertToMomentFormat function', function () { + var format, momentFormat; + + format = 'M/d/yy'; + momentFormat = 'M/DD/YYYY'; + expect(utils.convertToMomentFormat(format)).toBe(momentFormat); + }); + + it('Check "filterFormData" method', function () { + var suffix = 'prepared-for-send', + separator = '-', + data = { + key: 'value-prepared-before-save' + }; + expect(utils.filterFormData(data, suffix, separator)).toEqual(data); + expect(utils.filterFormData(data, suffix)).toEqual(data); + expect(utils.filterFormData(data)).toEqual(data); + expect(utils.filterFormData()).toEqual({}); + }); + + it('Check convertToMomentFormat function for all Magento supported locales', function () { + + var fixture, + localeValues, + format, + expectedValue, + momentFormat, + dt, + m, + p; + + fixture = { + 'af_ZA': { + 'locale': 'af_ZA', + 'localeInfo': { + 'format': 'y-MM-dd', + 'expectedValue': '2016-11-17' + } + }, + 'az_Latn_AZ': { + 'locale': 'az_Latn_AZ', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'id_ID': { + 'locale': 'id_ID', + 'localeInfo': { + 'format': 'dd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'ms_Latn_MY': { + 'locale': 'ms_Latn_MY', + 'localeInfo': { + 'format': 'd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'bs_Latn_BA': { + 'locale': 'bs_Latn_BA', + 'localeInfo': { + 'format': 'dd.MM.yy.', + 'expectedValue': '17.11.2016.' + } + }, + 'ca_ES': { + 'locale': 'ca_ES', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'cy_GB': { + 'locale': 'cy_GB', + 'localeInfo': { + 'format': 'dd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'da_DK': { + 'locale': 'da_DK', + 'localeInfo': { + 'format': 'dd/MM/y', + 'expectedValue': '17/11/2016' + } + }, + 'de_DE': { + 'locale': 'de_DE', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'de_CH': { + 'locale': 'de_CH', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'de_AT': { + 'locale': 'de_AT', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'et_EE': { + 'locale': 'et_EE', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'en_AU': { + 'locale': 'en_AU', + 'localeInfo': { + 'format': 'd/MM/y', + 'expectedValue': '17/11/2016' + } + }, + 'en_CA': { + 'locale': 'en_CA', + 'localeInfo': { + 'format': 'y-MM-dd', + 'expectedValue': '2016-11-17' + } + }, + 'en_IE': { + 'locale': 'en_IE', + 'localeInfo': { + 'format': 'dd/MM/y', + 'expectedValue': '17/11/2016' + } + }, + 'en_NZ': { + 'locale': 'en_NZ', + 'localeInfo': { + 'format': 'd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'en_GB': { + 'locale': 'en_GB', + 'localeInfo': { + 'format': 'dd/MM/y', + 'expectedValue': '17/11/2016' + } + }, + 'en_US': { + 'locale': 'en_US', + 'localeInfo': { + 'format': 'M/d/yy', + 'expectedValue': '11/17/2016' + } + }, + 'es_AR': { + 'locale': 'es_AR', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'es_CL': { + 'locale': 'es_CL', + 'localeInfo': { + 'format': 'dd-MM-yy', + 'expectedValue': '17-11-2016' + } + }, + 'es_CO': { + 'locale': 'es_CO', + 'localeInfo': { + 'format': 'd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'es_CR': { + 'locale': 'es_CR', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'es_ES': { + 'locale': 'es_ES', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'es_MX': { + 'locale': 'es_MX', + 'localeInfo': { + 'format': 'dd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'es_PA': { + 'locale': 'es_PA', + 'localeInfo': { + 'format': 'MM/dd/yy', + 'expectedValue': '11/17/2016' + } + }, + 'es_PE': { + 'locale': 'es_PE', + 'localeInfo': { + 'format': 'd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'es_VE': { + 'locale': 'es_VE', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'eu_ES': { + 'locale': 'eu_ES', + 'localeInfo': { + 'format': 'y/MM/dd', + 'expectedValue': '2016/11/17' + } + }, + 'fil_PH': { + 'locale': 'fil_PH', + 'localeInfo': { + 'format': 'M/d/yy', + 'expectedValue': '11/17/2016' + } + }, + 'fr_BE': { + 'locale': 'fr_BE', + 'localeInfo': { + 'format': 'd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'fr_CA': { + 'locale': 'fr_CA', + 'localeInfo': { + 'format': 'yy-MM-dd', + 'expectedValue': '2016-11-17' + } + }, + 'fr_FR': { + 'locale': 'fr_FR', + 'localeInfo': { + 'format': 'dd/MM/y', + 'expectedValue': '17/11/2016' + } + }, + 'gl_ES': { + 'locale': 'gl_ES', + 'localeInfo': { + 'format': 'dd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'hr_HR': { + 'locale': 'hr_HR', + 'localeInfo': { + 'format': 'dd.MM.y.', + 'expectedValue': '17.11.2016.' + } + }, + 'it_IT': { + 'locale': 'it_IT', + 'localeInfo': { + 'format': 'dd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'it_CH': { + 'locale': 'it_CH', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'sw_KE': { + 'locale': 'sw_KE', + 'localeInfo': { + 'format': 'dd/MM/y', + 'expectedValue': '17/11/2016' + } + }, + 'lv_LV': { + 'locale': 'lv_LV', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'lt_LT': { + 'locale': 'lt_LT', + 'localeInfo': { + 'format': 'y-MM-dd', + 'expectedValue': '2016-11-17' + } + }, + 'hu_HU': { + 'locale': 'hu_HU', + 'localeInfo': { + 'format': 'y. MM. dd.', + 'expectedValue': '2016. 11. 17.' + } + }, + 'nl_BE': { + 'locale': 'nl_BE', + 'localeInfo': { + 'format': 'd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'nl_NL': { + 'locale': 'nl_NL', + 'localeInfo': { + 'format': 'dd-MM-yy', + 'expectedValue': '17-11-2016' + } + }, + 'nb_NO': { + 'locale': 'nb_NO', + 'localeInfo': { + 'format': 'dd.MM.y', + 'expectedValue': '17.11.2016' + } + }, + 'nn_NO': { + 'locale': 'nn_NO', + 'localeInfo': { + 'format': 'dd.MM.y', + 'expectedValue': '17.11.2016' + } + }, + 'pl_PL': { + 'locale': 'pl_PL', + 'localeInfo': { + 'format': 'dd.MM.y', + 'expectedValue': '17.11.2016' + } + }, + 'pt_BR': { + 'locale': 'pt_BR', + 'localeInfo': { + 'format': 'dd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'pt_PT': { + 'locale': 'pt_PT', + 'localeInfo': { + 'format': 'dd/MM/yy', + 'expectedValue': '17/11/2016' + } + }, + 'ro_RO': { + 'locale': 'ro_RO', + 'localeInfo': { + 'format': 'dd.MM.y', + 'expectedValue': '17.11.2016' + } + }, + 'sq_AL': { + 'locale': 'sq_AL', + 'localeInfo': { + 'format': 'd.M.yy', + 'expectedValue': '17.11.2016' + } + }, + 'sk_SK': { + 'locale': 'sk_SK', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'sl_SI': { + 'locale': 'sl_SI', + 'localeInfo': { + 'format': 'd. MM. yy', + 'expectedValue': '17. 11. 2016' + } + }, + 'fi_FI': { + 'locale': 'fi_FI', + 'localeInfo': { + 'format': 'd.M.y', + 'expectedValue': '17.11.2016' + } + }, + 'sv_SE': { + 'locale': 'sv_SE', + 'localeInfo': { + 'format': 'y-MM-dd', + 'expectedValue': '2016-11-17' + } + }, + 'vi_VN': { + 'locale': 'vi_VN', + 'localeInfo': { + 'format': 'dd/MM/y', + 'expectedValue': '17/11/2016' + } + }, + 'tr_TR': { + 'locale': 'tr_TR', + 'localeInfo': { + 'format': 'd.MM.y', + 'expectedValue': '17.11.2016' + } + }, + 'is_IS': { + 'locale': 'is_IS', + 'localeInfo': { + 'format': 'd.M.y', + 'expectedValue': '17.11.2016' + } + }, + 'cs_CZ': { + 'locale': 'cs_CZ', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'el_GR': { + 'locale': 'el_GR', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'be_BY': { + 'locale': 'be_BY', + 'localeInfo': { + 'format': 'd.M.yy', + 'expectedValue': '17.11.2016' + } + }, + 'bg_BG': { + 'locale': 'bg_BG', + 'localeInfo': { + 'format': 'd.MM.yy г.', + 'expectedValue': '17.11.2016 г.' + } + }, + 'mk_MK': { + 'locale': 'mk_MK', + 'localeInfo': { + 'format': 'dd.M.yy', + 'expectedValue': '17.11.2016' + } + }, + 'mn_Cyrl_MN': { + 'locale': 'mn_Cyrl_MN', + 'localeInfo': { + 'format': 'y-MM-dd', + 'expectedValue': '2016-11-17' + } + }, + 'ru_RU': { + 'locale': 'ru_RU', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'sr_Cyrl_RS': { + 'locale': 'sr_Cyrl_RS', + 'localeInfo': { + 'format': 'd.M.yy.', + 'expectedValue': '17.11.2016.' + } + }, + 'uk_UA': { + 'locale': 'uk_UA', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'he_IL': { + 'locale': 'he_IL', + 'localeInfo': { + 'format': 'd.M.y', + 'expectedValue': '17.11.2016' + } + }, + 'ar_DZ': { + 'locale': 'ar_DZ', + 'localeInfo': { + 'format': 'd‏/M‏/y', + 'expectedValue': '17‏/11‏/2016' + } + }, + 'ar_KW': { + 'locale': 'ar_KW', + 'localeInfo': { + 'format': 'd‏/M‏/y', + 'expectedValue': '17‏/11‏/2016' + } + }, + 'ar_MA': { + 'locale': 'ar_MA', + 'localeInfo': { + 'format': 'd‏/M‏/y', + 'expectedValue': '17‏/11‏/2016' + } + }, + 'ar_SA': { + 'locale': 'ar_SA', + 'localeInfo': { + 'format': 'd‏/M‏/y', + 'expectedValue': '17‏/11‏/2016' + } + }, + 'ar_EG': { + 'locale': 'ar_EG', + 'localeInfo': { + 'format': 'd‏/M‏/y', + 'expectedValue': '17‏/11‏/2016' + } + }, + 'fa_IR': { + 'locale': 'fa_IR', + 'localeInfo': { + 'format': 'y/M/d G', + 'expectedValue': '2016/11/17 G' + } + }, + 'hi_IN': { + 'locale': 'hi_IN', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'bn_BD': { + 'locale': 'bn_BD', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'gu_IN': { + 'locale': 'gu_IN', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'th_TH': { + 'locale': 'th_TH', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'lo_LA': { + 'locale': 'lo_LA', + 'localeInfo': { + 'format': 'd/M/y', + 'expectedValue': '17/11/2016' + } + }, + 'ka_GE': { + 'locale': 'ka_GE', + 'localeInfo': { + 'format': 'dd.MM.yy', + 'expectedValue': '17.11.2016' + } + }, + 'km_KH': { + 'locale': 'km_KH', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'zh_Hans_CN': { + 'locale': 'zh_Hans_CN', + 'localeInfo': { + 'format': 'yy/M/d', + 'expectedValue': '2016/11/17' + } + }, + 'zh_Hant_HK': { + 'locale': 'zh_Hant_HK', + 'localeInfo': { + 'format': 'd/M/yy', + 'expectedValue': '17/11/2016' + } + }, + 'zh_Hant_TW': { + 'locale': 'zh_Hant_TW', + 'localeInfo': { + 'format': 'y/M/d', + 'expectedValue': '2016/11/17' + } + }, + 'ja_JP': { + 'locale': 'ja_JP', + 'localeInfo': { + 'format': 'y/MM/dd', + 'expectedValue': '2016/11/17' + } + }, + 'ko_KR': { + 'locale': 'ko_KR', + 'localeInfo': { + 'format': 'yy. M. d.', + 'expectedValue': '2016. 11. 17.' + } + } + }; + + for (p in fixture) { + if (fixture.hasOwnProperty(p)) { + localeValues = fixture[p]; + format = localeValues.localeInfo.format; + expectedValue = localeValues.localeInfo.expectedValue; + momentFormat = utils.convertToMomentFormat(format); + dt = moment('2016-11-17'); + m = moment(dt, momentFormat); + + expect(m.format(momentFormat)).toBe(expectedValue); + } + } + }); + }); +}); diff --git a/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-jsbuild.test.js b/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-jsbuild.test.js index 9ca9dbf0d440e..844b948eff926 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-jsbuild.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-jsbuild.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js b/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js index 73044c95c634b..b54ea1f20b906 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/requirejs/static-text.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/tests/lib/mage/requirejs/statistician.test.js b/dev/tests/js/jasmine/tests/lib/mage/requirejs/statistician.test.js index 1cbe51f83c995..8b5864e21a8a6 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/requirejs/statistician.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/requirejs/statistician.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/js/jasmine/tests/lib/mage/scripts.test.js b/dev/tests/js/jasmine/tests/lib/mage/scripts.test.js index e82d229fea125..706f3b2e3731b 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/scripts.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/scripts.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/js/jasmine/tests/lib/mage/template.test.js b/dev/tests/js/jasmine/tests/lib/mage/template.test.js index ebdf57a0d4a88..1d7680c56c9f0 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/template.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/template.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ 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 c3a355babced8..6df64eb9a53b2 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/validation.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/validation.test.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ define([ diff --git a/dev/tests/static/framework/Magento/Sniffs/Arrays/ShortArraySyntaxSniff.php b/dev/tests/static/framework/Magento/Sniffs/Arrays/ShortArraySyntaxSniff.php index 09edad817802d..4325c480b6633 100644 --- a/dev/tests/static/framework/Magento/Sniffs/Arrays/ShortArraySyntaxSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/Arrays/ShortArraySyntaxSniff.php @@ -1,6 +1,6 @@ getTokens(); + + // Make sure this is the first open tag + $previousOpenTag = $phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)); + if ($previousOpenTag !== false) { + return; + } + + $tokenCount = 0; + $currentLineContent = ''; + $currentLine = 1; + + for (; $tokenCount < $phpcsFile->numTokens; $tokenCount++) { + if ($tokens[$tokenCount]['line'] === $currentLine) { + $currentLineContent .= $tokens[$tokenCount]['content']; + } else { + $this->checkIfFirstArgumentConstant($phpcsFile, ($tokenCount - 1), $currentLineContent); + $currentLineContent = $tokens[$tokenCount]['content']; + $currentLine++; + } + } + + $this->checkIfFirstArgumentConstant($phpcsFile, ($tokenCount - 1), $currentLineContent); + } + + /** + * Checks if first argument of \Magento\Framework\Phrase or translation function is a constant + * + * @param \PHP_CodeSniffer_File $phpcsFile + * @param int $stackPtr + * @param string $lineContent + * @return void + */ + private function checkIfFirstArgumentConstant( + \PHP_CodeSniffer_File $phpcsFile, + $stackPtr, + $lineContent + ) { + $previousLineRegexp = '/(__|Phrase)\($/im'; + $currentLineRegexp = '/(__|Phrase)\(.+\)/'; $currentLineMatch = preg_match($currentLineRegexp, $lineContent) !== 0; $previousLineMatch = preg_match($previousLineRegexp, $this->previousLineContent) !== 0; $this->previousLineContent = $lineContent; $error = 'Constants are not allowed as the first argument of translation function, use string literal instead'; - $constantRegexp = '[^\'"]+::[A-Z_0-9]+.*'; + $constantRegexp = '[^\$\'"]+::[A-Z_0-9]+.*'; if ($currentLineMatch) { - $variableRegexp = "~__\({$constantRegexp}\)|Phrase\({$constantRegexp}\)~"; + $variableRegexp = "/(__|Phrase)\({$constantRegexp}\)/"; if (preg_match($variableRegexp, $lineContent) !== 0) { $phpcsFile->addError($error, $stackPtr, 'VariableTranslation'); } } else if ($previousLineMatch) { - $variableRegexp = "~^\s+{$constantRegexp}~"; + $variableRegexp = "/^{$constantRegexp}/"; if (preg_match($variableRegexp, $lineContent) !== 0) { $phpcsFile->addError($error, $stackPtr, 'VariableTranslation'); } diff --git a/dev/tests/static/framework/Magento/Sniffs/Whitespace/EmptyLineMissedSniff.php b/dev/tests/static/framework/Magento/Sniffs/Whitespace/EmptyLineMissedSniff.php index 7538074d91d08..fcdfa0001be3d 100644 --- a/dev/tests/static/framework/Magento/Sniffs/Whitespace/EmptyLineMissedSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/Whitespace/EmptyLineMissedSniff.php @@ -1,6 +1,6 @@ getCommand() . ' --version', $output, $exitCode); return $exitCode === 0; } @@ -71,22 +70,37 @@ public function canRun() */ public function run(array $whiteList) { - $blackListStr = ' '; + $blacklistedDirs = []; + $blacklistedFileNames = []; foreach ($this->blacklist as $file) { $file = escapeshellarg(trim($file)); if (!$file) { continue; } - $blackListStr .= '--exclude ' . $file . ' '; + $ext = pathinfo($file, PATHINFO_EXTENSION); + if ($ext != '') { + $blacklistedFileNames[] = $file; + } else { + $blacklistedDirs[] = '--exclude ' . $file . ' '; + } } - $vendorDir = require BP . '/app/etc/vendor_path.php'; - $command = 'php ' . BP . '/' . $vendorDir . '/bin/phpcpd' . ' --log-pmd ' . escapeshellarg( - $this->reportFile - ) . ' --names-exclude "*Test.php" --min-lines 13' . $blackListStr . ' ' . implode(' ', $whiteList); - + $command = $this->getCommand() . ' --log-pmd ' . escapeshellarg($this->reportFile) + . ' --names-exclude ' . join(',', $blacklistedFileNames) . ' --min-lines 13 ' . join(' ', $blacklistedDirs) + . ' ' . implode(' ', $whiteList); exec($command, $output, $exitCode); return !(bool)$exitCode; } + + /** + * Get PHPCPD command + * + * @return string + */ + private function getCommand() + { + $vendorDir = require BP . '/app/etc/vendor_path.php'; + return 'php ' . BP . '/' . $vendorDir . '/bin/phpcpd'; + } } diff --git a/dev/tests/static/framework/Magento/TestFramework/CodingStandard/Tool/ExtensionInterface.php b/dev/tests/static/framework/Magento/TestFramework/CodingStandard/Tool/ExtensionInterface.php index 5dd33c9faf117..55b008e3a0ec8 100644 --- a/dev/tests/static/framework/Magento/TestFramework/CodingStandard/Tool/ExtensionInterface.php +++ b/dev/tests/static/framework/Magento/TestFramework/CodingStandard/Tool/ExtensionInterface.php @@ -1,6 +1,6 @@ markTestSkipped('Skipped due to MAGETWO-44919'); + $this->markTestSkipped('Skipped due to MAGETWO-45033'); } $xmlFile = $this->_getKnownInvalidXml(); $schema = $this->_getXsd(); @@ -46,7 +46,7 @@ public function testSchemaUsingInvalidXml($expectedErrors = null) public function testFileSchemaUsingPartialXml() { if (!function_exists('libxml_set_external_entity_loader')) { - $this->markTestSkipped('Skipped due to MAGETWO-44919'); + $this->markTestSkipped('Skipped due to MAGETWO-45033'); } $xmlFile = $this->_getKnownValidPartialXml(); if ($xmlFile === null) { diff --git a/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php b/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php index 2d9dce0788500..1484237031f0c 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php +++ b/dev/tests/static/framework/Magento/TestFramework/Integrity/Library/Injectable.php @@ -1,6 +1,6 @@ getPhpFiles( - Files::INCLUDE_APP_CODE - | Files::INCLUDE_PUB_CODE - | Files::INCLUDE_LIBS - | Files::INCLUDE_TEMPLATES - | Files::INCLUDE_TESTS - | Files::AS_DATA_SET - | Files::INCLUDE_NON_CLASSES - )); + $phpFiles = Files::composeDataSets($phpFiles); + $phpFiles = array_intersect_key($phpFiles, $fileUtilities->getPhpFiles()); } } else { - $phpFiles = $fileHelper->getPhpFiles( - Files::INCLUDE_APP_CODE - | Files::INCLUDE_PUB_CODE - | Files::INCLUDE_LIBS - | Files::INCLUDE_TEMPLATES - | Files::INCLUDE_TESTS - | Files::AS_DATA_SET - | Files::INCLUDE_NON_CLASSES - ); + $phpFiles = $fileUtilities->getPhpFiles(); } return $phpFiles; } + + /** + * Get changed content. + * + * @param string $fileName + * @return string + */ + public static function getChangedContent($fileName) + { + $data = []; + $extension = self::getFileExtension($fileName); + $fileName = ltrim(str_replace(BP, '', $fileName), DIRECTORY_SEPARATOR); + $changedFilesContentFile = BP . sprintf(self::CHANGED_FILES_CONTENT_FILE, $extension); + if (file_exists($changedFilesContentFile)) { + $changedContent = file_get_contents($changedFilesContentFile); + $data = json_decode($changedContent, true); + } + + return isset($data[$fileName]) ? $data[$fileName] : ''; + } + + /** + * Get file extension. + * + * @param string $fileName + * @return string + */ + public static function getFileExtension($fileName) + { + $fileInfo = pathinfo($fileName); + return isset($fileInfo['extension']) ? $fileInfo['extension'] : 'unknown'; + } } diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/CodeCheck.php b/dev/tests/static/framework/Magento/TestFramework/Utility/CodeCheck.php index c350bd129b5dd..77c3ce3bd8ddf 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Utility/CodeCheck.php +++ b/dev/tests/static/framework/Magento/TestFramework/Utility/CodeCheck.php @@ -1,6 +1,6 @@ fileUtilities = $fileUtilities; + $this->regexIteratorFactory = $regexIteratorFactory; + } + + /** + * Get list of PHP files + * + * @return array + * @throws \Exception + */ + public function getPhpFiles() + { + $files = array_merge( + $this->fileUtilities->getPhpFiles( + Files::INCLUDE_APP_CODE + | Files::INCLUDE_PUB_CODE + | Files::INCLUDE_LIBS + | Files::INCLUDE_TEMPLATES + | Files::INCLUDE_TESTS + | Files::INCLUDE_NON_CLASSES + ), + $this->getSetupPhpFiles() + ); + return Files::composeDataSets($files); + } + + /** + * Get list of PHP files in setup application + * + * @param int $flags + * @return array + */ + private function getSetupPhpFiles() + { + $files = []; + $regexIterator = $this->regexIteratorFactory->create( + BP . '/setup', + '/.*php^/' + ); + foreach ($regexIterator as $file) { + $files = array_merge($files, [$file]); + } + return $files; + } +} diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/File/RegexIteratorFactory.php b/dev/tests/static/framework/Magento/TestFramework/Utility/File/RegexIteratorFactory.php new file mode 100644 index 0000000000000..64f496599ebb8 --- /dev/null +++ b/dev/tests/static/framework/Magento/TestFramework/Utility/File/RegexIteratorFactory.php @@ -0,0 +1,26 @@ + [ + * function_name_1, + * function_name_2, + * function_name_3, + * ], + * line_number => [ + * function_name_1, + * function_name_2, + * function_name_3, + * ], + * ] + * + * @param string $filePath + * @param string[] $functions + * @return array + */ + public function detect($filePath, $functions) + { + $result = []; + $regexp = $this->composeRegexp($functions); + + if (!$regexp) { + return $result; + } + + $fileContent = \Magento\TestFramework\Utility\ChangedFiles::getChangedContent($filePath); + $file = file($filePath); + + return $fileContent + ? $this->grepChangedContent($file, $regexp, $functions, $fileContent) + : $this->grepFile($file, $regexp); + } + + /** + * Grep only changed content. + * + * @param array $file + * @param string $regexp + * @param string[] $functions + * @param string $fileContent + * @return array + */ + public function grepChangedContent(array $file, $regexp, $functions, $fileContent) + { + $result = []; + $matches = preg_grep($regexp, explode("\n", $fileContent)); + if (!empty($matches)) { + foreach ($matches as $line) { + $actualFunctions = []; + foreach ($functions as $function) { + if (false !== strpos($line, $function)) { + $actualFunctions[] = $function; + } + } + $result[array_search($line . "\n", $file) + 1] = $actualFunctions; + } + } + + return $result; + } + + /** + * Grep File. + * + * @param array $file + * @param string $regexp + * @return array + */ + public function grepFile(array $file, $regexp) + { + $result = []; + array_unshift($file, ''); + $lines = preg_grep($regexp, $file); + foreach ($lines as $lineNumber => $line) { + if (preg_match_all($regexp, $line, $matches)) { + $result[$lineNumber] = $matches[1]; + } + } + + return $result; + } + + /** + * Compose regular expression + * + * @param array $functions + * @return string + */ + private function composeRegexp(array $functions) + { + if (empty($functions)) { + return ''; + } + return '/(?|::)\b(' . join('|', $functions) . ')\s*\(/i'; + } +} diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/XssOutputValidator.php b/dev/tests/static/framework/Magento/TestFramework/Utility/XssOutputValidator.php index 1e0d684c1242d..c9dc71c962448 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Utility/XssOutputValidator.php +++ b/dev/tests/static/framework/Magento/TestFramework/Utility/XssOutputValidator.php @@ -1,6 +1,6 @@ /sim', '\1', $command); - return ltrim(explode(';', $command)[0], 'echo'); + return trim(ltrim(explode(';', $command)[0], 'echo')); } /** @@ -309,7 +309,18 @@ private function replacePhpQuoteWithPlaceholders($fileContent) $phpBlock ); - $this->addQuoteOriginsReplacements($phpBlockQuoteReplaced); + $this->addQuoteOriginsReplacements( + $phpBlockQuoteReplaced, + [ + '/([^\\\\])([\'])(.*?)([^\\\\])([\'])/sim' + ] + ); + $this->addQuoteOriginsReplacements( + $phpBlockQuoteReplaced, + [ + '/([^\\\\])(["])(.*?)([^\\\\])(["])/sim', + ] + ); $origins[] = $phpBlock; $replacements[] = str_replace( @@ -354,15 +365,11 @@ private function replacePhpCommentsWithPlaceholders($fileContent) * Add replacements for expressions in single and double quotes * * @param string $phpBlock + * @param array $patterns * @return void */ - private function addQuoteOriginsReplacements($phpBlock) + private function addQuoteOriginsReplacements($phpBlock, array $patterns) { - $patterns = [ - '/([^\\\\])(["])(.*?)([^\\\\])(["])/sim', - '/([^\\\\])([\'])(.*?)([^\\\\])([\'])/sim' - ]; - foreach ($patterns as $pattern) { if (preg_match_all($pattern, $phpBlock, $quoteMatches, PREG_SET_ORDER)) { foreach ($quoteMatches as $quoteMatch) { diff --git a/dev/tests/static/framework/Magento/ruleset.xml b/dev/tests/static/framework/Magento/ruleset.xml index c1b7fb98bd296..a636b13c7ff99 100644 --- a/dev/tests/static/framework/Magento/ruleset.xml +++ b/dev/tests/static/framework/Magento/ruleset.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/autoload.php b/dev/tests/static/framework/autoload.php index 479225bef078f..866015fed9cdc 100644 --- a/dev/tests/static/framework/autoload.php +++ b/dev/tests/static/framework/autoload.php @@ -1,9 +1,11 @@ addPsr4('Magento\\', $baseDir . '/var/generation/Magento/'); + +$generatedCode = DirectoryList::getDefaultConfig()[DirectoryList::GENERATED_CODE][DirectoryList::PATH]; +$autoloadWrapper->addPsr4('Magento\\', $baseDir . '/' . $generatedCode . '/Magento/'); diff --git a/dev/tests/static/framework/bootstrap.php b/dev/tests/static/framework/bootstrap.php index 737ae90cbcd4c..e20e88c620c54 100644 --- a/dev/tests/static/framework/bootstrap.php +++ b/dev/tests/static/framework/bootstrap.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/ConstantUsageSniffTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/ConstantUsageSniffTest.php new file mode 100644 index 0000000000000..72dc0ab31cfcb --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/ConstantUsageSniffTest.php @@ -0,0 +1,96 @@ +fileMock = $this->getMock(\PHP_CodeSniffer_File::class, [], [], '', false); + $this->constantUsageSniff = new ConstantUsageSniff(); + } + + /** + * @param string $file + * @param int $numIncorrectUsages + * @dataProvider processDataProvider + */ + public function testProcessIncorrectArguments($file, $numIncorrectUsages) + { + $stackPtr = 10; + $fileContent = file_get_contents(__DIR__ . '/_files/' . $file); + $tokens = $this->tokenizeString($fileContent); + $this->fileMock->expects($this->once()) + ->method('findPrevious') + ->with( + T_OPEN_TAG, + $stackPtr - 1 + ) + ->willReturn(false); + $this->fileMock->expects($this->once()) + ->method('getTokens') + ->willReturn($tokens); + $this->fileMock->numTokens = count($tokens); + $this->fileMock->expects($this->exactly($numIncorrectUsages)) + ->method('addError') + ->with( + 'Constants are not allowed as the first argument of translation function, use string literal instead', + $this->anything(), + 'VariableTranslation' + ); + $this->constantUsageSniff->process($this->fileMock, $stackPtr); + } + + /** + * Get tokens for a string + * + * @param string $fileContent + * @return array + */ + private function tokenizeString($fileContent) + { + $lineNumber = 1; + $tokens = token_get_all($fileContent); + $snifferTokens = []; + for ($i = 0; $i < count($tokens); $i++) { + $content = is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i]; + $snifferTokens[$i]['line'] = $lineNumber; + $snifferTokens[$i]['content'] = $content; + $trimmedContent = trim($content, ' '); + if ($trimmedContent == PHP_EOL || $trimmedContent == PHP_EOL . PHP_EOL) { + $lineNumber++; + } + } + return $snifferTokens; + } + + /** + * @return array + */ + public function processDataProvider() + { + return [ + [ + 'incorrect_arguments.txt', + 9 + ], + [ + 'correct_arguments.txt', + 0 + ] + ]; + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/correct_arguments.txt b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/correct_arguments.txt new file mode 100644 index 0000000000000..e8facf116fa37 --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Sniffs/Translation/_files/correct_arguments.txt @@ -0,0 +1,29 @@ +codeCheck = new CodeCheck(); + } + + /** + * @param string $fileContent + * @param bool $isClassUsed + * @dataProvider isClassUsedDataProvider + */ + public function testIsClassUsed($fileContent, $isClassUsed) + { + $this->assertEquals( + $isClassUsed, + $this->codeCheck->isClassUsed('MyClass', $fileContent) + ); + } + + /** + * @return array + */ + public function isClassUsedDataProvider() + { + return [ + [file_get_contents(__DIR__ . '/_files/create_new_instance.txt'), true], + [file_get_contents(__DIR__ . '/_files/create_new_instance2.txt'), true], + [file_get_contents(__DIR__ . '/_files/create_new_instance3.txt'), true], + [file_get_contents(__DIR__ . '/_files/class_name_in_namespace_and_variable_name.txt'), false], + [file_get_contents(__DIR__ . '/_files/extends.txt'), true], + [file_get_contents(__DIR__ . '/_files/extends2.txt'), true], + [file_get_contents(__DIR__ . '/_files/use.txt'), true], + [file_get_contents(__DIR__ . '/_files/use2.txt'), true] + ]; + } + + /** + * @param string $fileContent + * @param bool $isDirectDescendant + * @dataProvider isDirectDescendantDataProvider + */ + public function testIsDirectDescendant($fileContent, $isDirectDescendant) + { + $this->assertEquals( + $isDirectDescendant, + $this->codeCheck->isDirectDescendant($fileContent, 'MyClass') + ); + } + + /** + * @return array + */ + public function isDirectDescendantDataProvider() + { + return [ + [file_get_contents(__DIR__ . '/_files/extends.txt'), true], + [file_get_contents(__DIR__ . '/_files/extends2.txt'), true], + [file_get_contents(__DIR__ . '/_files/implements.txt'), true], + [file_get_contents(__DIR__ . '/_files/implements2.txt'), true] + ]; + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/Test/Utility/File/_files/class_name_in_namespace_and_variable_name.txt b/dev/tests/static/framework/tests/unit/testsuite/Magento/Test/Utility/File/_files/class_name_in_namespace_and_variable_name.txt new file mode 100644 index 0000000000000..7d33e2eae047b --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/Test/Utility/File/_files/class_name_in_namespace_and_variable_name.txt @@ -0,0 +1,8 @@ + diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/VirtualType/_files/etc/di.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/VirtualType/_files/etc/di.xml index a2eda94d38027..8d8f01b5a9ae8 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/VirtualType/_files/etc/di.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/VirtualType/_files/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_external_dependency.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_external_dependency.xml index 63493ef8b5d95..11ca402d144b6 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_external_dependency.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_external_dependency.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_in_module_dependency.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_in_module_dependency.xml index c4b0c3cb5b0ea..c18cc3cca959a 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_in_module_dependency.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_in_module_dependency.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_no_dependency.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_no_dependency.xml index 04c02acb98b12..8f85798987b5f 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_no_dependency.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_no_dependency.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_virtual_dependency.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_virtual_dependency.xml index de96c5d13ad66..8e575d628718c 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_virtual_dependency.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/di_virtual_dependency.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle.xml index 8f27101b04f2d..f059e2cbeaa12 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_parent.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_parent.xml index 009a16e8b261f..e08eae0702853 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_parent.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_parent.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_update.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_update.xml index 56ffa1d64e058..ff1212cdce479 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_update.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_handle_update.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_reference.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_reference.xml index 7789b86ee2190..3f7fdb2745f19 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_reference.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/_files/layout_reference.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/JsHint/CommandTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/JsHint/CommandTest.php index 0bafef54a634c..a455c6489c684 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/JsHint/CommandTest.php +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/JsHint/CommandTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config.xml index 2f39c3b27ae1e..e5c070ff78cfd 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config_additional.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config_additional.xml index 39ad0224c49eb..87285efbb057a 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config_additional.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/config_additional.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_whitelist_path.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_whitelist_path.xml index d1a351a4150f4..a8f779713cb08 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_whitelist_path.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_whitelist_path.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_words_config.xml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_words_config.xml index d655220de0cd8..7fab5dd61de58 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_words_config.xml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/empty_words_config.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/buffy.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/buffy.php index 3370d5772687f..7ef667b2f46f2 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/buffy.php +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/buffy.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/twilight/eclipse.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/twilight/eclipse.php index a9035aafcee7c..fcb3eb247f9b2 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/twilight/eclipse.php +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Inspection/_files/words_finder/twilight/eclipse.php @@ -1,6 +1,6 @@ objectManager = new ObjectManager($this); + $this->fileUtilitiesMock = $this->getMock(Files::class, [], [], '', false); + $this->regexIteratorFactoryMock = $this->getMock(RegexIteratorFactory::class, [], [], '', false); + $this->file = $this->objectManager->getObject( + File::class, + [ + 'fileUtilities' => $this->fileUtilitiesMock, + 'regexIteratorFactory' => $this->regexIteratorFactoryMock + ] + ); + } + + public function testGetPhpFiles() + { + $appFiles = [ + 'file1', + 'file2' + ]; + $setupFiles = [ + 'file3' + ]; + $expected = [ + 'file1' => ['file1'], + 'file2' => ['file2'], + 'file3' => ['file3'] + ]; + $iteratorMock = $this->getMock(\IteratorAggregate::class, [], [], '', false); + $iteratorMock->expects($this->any()) + ->method('getIterator') + ->willReturn(new \ArrayIterator($setupFiles)); + $this->regexIteratorFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($iteratorMock); + $this->fileUtilitiesMock->expects($this->once()) + ->method('getPhpFiles') + ->with( + Files::INCLUDE_APP_CODE + | Files::INCLUDE_PUB_CODE + | Files::INCLUDE_LIBS + | Files::INCLUDE_TEMPLATES + | Files::INCLUDE_TESTS + | Files::INCLUDE_NON_CLASSES + ) + ->willReturn($appFiles); + $this->assertEquals($expected, $this->file->getPhpFiles()); + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FunctionDetectorTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FunctionDetectorTest.php new file mode 100644 index 0000000000000..3bc26b3b44e3c --- /dev/null +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/FunctionDetectorTest.php @@ -0,0 +1,22 @@ + ['strtoupper', 'strtolower'], + 3 => ['foo'], + 4 => ['foo'], + ]; + $functionDetector = new FunctionDetector(); + $lines = $functionDetector->detect($fixturePath, ['foo', 'strtoupper', 'test', 'strtolower']); + $this->assertEquals($expectedResults, $lines); + } +} diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/XssOutputValidatorTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/XssOutputValidatorTest.php index d307f6ee1b99b..7bc7187ed9a4a 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/XssOutputValidatorTest.php +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/XssOutputValidatorTest.php @@ -1,6 +1,6 @@ generateHash(foo($bar), $foo) +foo( + 'bar' +) +Foo::bar($foo, $this->getData('bar')) +$this->foo('bar') +Foo::foo() diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml index ae9b09dd9c631..1b569c718a59c 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Utility/_files/xss_safe.phtml @@ -1,6 +1,6 @@ " --base-path="" --repo="" @@ -34,13 +34,36 @@ $fileExtensions = explode(',', isset($options['file-extensions']) ? $options['file-extensions'] : 'php'); +include_once __DIR__ . '/framework/autoload.php'; + $mainline = 'mainline_' . (string)rand(0, 9999); $repo = getRepo($options, $mainline); +$branches = $repo->getBranches('--remotes'); +generateBranchesList($options['output-file'], $branches, $options['branch']); $changes = retrieveChangesAcrossForks($mainline, $repo, $options['branch']); $changedFiles = getChangedFiles($changes, $fileExtensions); generateChangedFilesList($options['output-file'], $changedFiles); +saveChangedFileContent($repo); cleanup($repo, $mainline); +/** + * Save changed file content. + * + * @param GitRepo $repo + * @return void + */ +function saveChangedFileContent(GitRepo $repo) +{ + $changedFilesContentFileName = BP . Magento\TestFramework\Utility\ChangedFiles::CHANGED_FILES_CONTENT_FILE; + foreach ($repo->getChangedContentFiles() as $key => $changedContentFile) { + $filePath = sprintf($changedFilesContentFileName, $key); + $oldContent = file_exists($filePath) ? file_get_contents($filePath) : '{}'; + $oldData = json_decode($oldContent, true); + $data = array_merge($oldData, $changedContentFile); + file_put_contents($filePath, json_encode($data)); + } +} + /** * Generates a file containing changed files * @@ -57,6 +80,25 @@ function generateChangedFilesList($outputFile, $changedFiles) fclose($changedFilesList); } +/** + * Generates a file containing origin branches + * + * @param string $outputFile + * @param array $branches + * @param string $branchName + * @return void + */ +function generateBranchesList($outputFile, $branches, $branchName) +{ + $branchOutputFile = str_replace('changed_files', 'branches', $outputFile); + $branchesList = fopen($branchOutputFile, 'w'); + fwrite($branchesList, $branchName . PHP_EOL); + foreach ($branches as $branch) { + fwrite($branchesList, substr(strrchr($branch, '/'), 1) . PHP_EOL); + } + fclose($branchesList); +} + /** * Gets list of changed files * @@ -84,7 +126,7 @@ function getChangedFiles(array $changes, array $fileExtensions) * * @param array $options * @param string $mainline - * @return array + * @return GitRepo * @throws Exception */ function getRepo($options, $mainline) @@ -149,6 +191,18 @@ class GitRepo */ private $remoteList = []; + /** + * Array of changed content files. + * + * Example: + * 'extension' => + * 'path_to_file/filename' => 'Content that was edited', + * 'path_to_file/filename2' => 'Content that was edited', + * + * @var array + */ + private $changedContentFiles = []; + /** * @param string $workTree absolute path to git project */ @@ -203,6 +257,19 @@ public function fetch($remoteAlias) $this->call(sprintf('fetch %s', $remoteAlias)); } + /** + * Returns branches + * + * @param string $source + * @return array|mixed + */ + public function getBranches($source = '--all') + { + $result = $this->call(sprintf('branch ' . $source)); + + return is_array($result) ? $result : []; + } + /** * Returns files changes between branch and HEAD * @@ -251,6 +318,9 @@ protected function filterChangedFiles(array $changes, $remoteAlias, $remoteBranc 'diff HEAD %s/%s -- %s', $remoteAlias, $remoteBranch, $this->workTree . '/' . $fileName) ); if ($result) { + if (!(isset($this->changedContentFiles[$fileName]))) { + $this->setChangedContentFile($result, $fileName); + } $filteredChanges[] = $fileName; } } @@ -261,6 +331,38 @@ protected function filterChangedFiles(array $changes, $remoteAlias, $remoteBranc return $filteredChanges; } + /** + * Set changed content for file. + * + * @param array $content + * @param string $fileName + * @return void + */ + private function setChangedContentFile(array $content, $fileName) + { + $changedContent = ''; + $extension = Magento\TestFramework\Utility\ChangedFiles::getFileExtension($fileName); + + foreach ($content as $item) { + if (strpos($item, '---') !== 0 && strpos($item, '-') === 0 && $line = ltrim($item, '-')) { + $changedContent .= $line . "\n"; + } + } + if ($changedContent !== '') { + $this->changedContentFiles[$extension][$fileName] = $changedContent; + } + } + + /** + * Get changed content files collection. + * + * @return array + */ + public function getChangedContentFiles() + { + return $this->changedContentFiles; + } + /** * Makes call ro git cli * diff --git a/dev/tests/static/phpunit-all.xml.dist b/dev/tests/static/phpunit-all.xml.dist index 605977260157d..b6f3f19dab061 100644 --- a/dev/tests/static/phpunit-all.xml.dist +++ b/dev/tests/static/phpunit-all.xml.dist @@ -3,7 +3,7 @@ /** * Run all available test suites * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/static/phpunit.xml.dist b/dev/tests/static/phpunit.xml.dist index 5b226e0d2bb40..c498348343540 100644 --- a/dev/tests/static/phpunit.xml.dist +++ b/dev/tests/static/phpunit.xml.dist @@ -3,7 +3,7 @@ /** * Default test suites declaration: run verification of coding standards and code integrity test suites * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ApiAnnotationTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ApiAnnotationTest.php deleted file mode 100644 index a1e7c25e3d600..0000000000000 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ApiAnnotationTest.php +++ /dev/null @@ -1,40 +0,0 @@ -getPaths(ComponentRegistrar::MODULE)); - - foreach (Files::init()->getFiles($modulePaths, '*.php', true) as $file) { - $fileContent = file_get_contents($file); - if (!preg_match($this->apiAnnotation, $fileContent)) { - $result[] = $file; - } - } - if (!empty($result)) { - $this->fail(sprintf( - 'Found %s file(s) without @api annotations under Api namespace: %s', - count($result), - PHP_EOL . implode(PHP_EOL, $result) - )); - } - } -} diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/CircularDependencyTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/CircularDependencyTest.php index bd34804c02637..f49fddddb11d3 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/CircularDependencyTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/CircularDependencyTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/_files/known_valid.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/_files/known_valid.xml index 445f91932e2ba..c83e66da61d60 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/_files/known_valid.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/_files/known_valid.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/CircularDependencyTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/CircularDependencyTest.php index 426279746b379..100ef425252ca 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/CircularDependencyTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/CircularDependencyTest.php @@ -2,7 +2,7 @@ /** * Scan source code for incorrect or undeclared modules dependencies * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php index 16cf02c62aa48..09a507c09fad5 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ClassesTest.php @@ -2,7 +2,7 @@ /** * Scan source code for references to classes and see if they indeed exist * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php index 430d72bf11c6e..52b1f4fa7dce5 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerLockTest.php @@ -1,6 +1,6 @@ _generationDir = $directoryList->getPath(DirectoryList::GENERATION); - $this->_compilationDir = $directoryList->getPath(DirectoryList::DI); + $this->_generationDir = $directoryList->getPath(DirectoryList::GENERATED_CODE); + $this->_compilationDir = $directoryList->getPath(DirectoryList::GENERATED_METADATA); $this->_command = 'php ' . $basePath . '/bin/magento setup:di:compile'; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ExceptionHierarchyTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ExceptionHierarchyTest.php index 7f31ea875d9af..8d8af1c1a5a23 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ExceptionHierarchyTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ExceptionHierarchyTest.php @@ -1,6 +1,6 @@ getDependencies($fileReflection), $tokens->getDependencies() ); - - $pattern = '#^(\\\\|)' . implode('|', $this->getForbiddenNamespaces()) . '\\\\#'; + $allowedNamespaces = str_replace('\\', '\\\\', implode('|', $this->getAllowedNamespaces())); + $pattern = '#Magento\\\\(?!' . $allowedNamespaces . ').*#'; foreach ($dependencies as $dependency) { - $dependencyPaths = explode('/', $dependency); + $dependencyPaths = explode('\\', $dependency); $dependencyPaths = array_slice($dependencyPaths, 2); - $dependency = implode('\\', $dependencyPaths); + $dependencyPath = implode('\\', $dependencyPaths); $libraryPaths = $componentRegistrar->getPaths(ComponentRegistrar::LIBRARY); foreach ($libraryPaths as $libraryPath) { - $filePath = str_replace('\\', '/', $libraryPath . '/' . $dependency . '.php'); + $filePath = str_replace('\\', '/', $libraryPath . '/' . $dependencyPath . '.php'); if (preg_match($pattern, $dependency) && !file_exists($filePath)) { $this->errors[$fileReflection->getFileName()][] = $dependency; } @@ -142,12 +162,11 @@ public function libraryDataProvider() $componentRegistrar = new ComponentRegistrar(); include_once $componentRegistrar->getPath(ComponentRegistrar::LIBRARY, 'magento/framework') . '/Option/ArrayInterface.php'; - $blackList = Files::init()->readLists(__DIR__ . '/_files/blacklist.txt'); + $blackList = Files::init()->readLists(__DIR__ . '/_files/blacklist*.txt'); $dataProvider = Files::init()->getPhpFiles(Files::INCLUDE_LIBS | Files::AS_DATA_SET); foreach ($dataProvider as $key => $data) { - $file = str_replace(BP . '/', '', $data[0]); - if (in_array($file, $blackList)) { + if (in_array($data[0], $blackList)) { unset($dataProvider[$key]); } else { include_once $data[0]; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/SystemConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/SystemConfigTest.php index eef34bf3f8e7c..9bba81ddd7483 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/SystemConfigTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/SystemConfigTest.php @@ -2,7 +2,7 @@ /** * Find "backend/system.xml" files and validate them * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity\Magento\Backend; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/FieldsetConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/FieldsetConfigTest.php index 136610ce44388..867655e30e9d7 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/FieldsetConfigTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/FieldsetConfigTest.php @@ -2,7 +2,7 @@ /** * Find "fieldset.xml" files and validate them * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity\Magento\Core\Model\Fieldset; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset.xml index a4a4305cba89a..87bccab9c0e9a 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset_file.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset_file.xml index 254b5b617765f..f106f2a105fab 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset_file.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/fieldset_file.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/invalid_fieldset.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/invalid_fieldset.xml index 1bf673812d0aa..97e0e3e09b9ca 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/invalid_fieldset.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Core/Model/Fieldset/_files/invalid_fieldset.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/ExtensibleInterfacesTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/ExtensibleInterfacesTest.php index 0519028c9ed78..65b44a047179b 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/ExtensibleInterfacesTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/ExtensibleInterfacesTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/invalid_partial.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/invalid_partial.xml index 04ddbe89772cf..462000280c8e8 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/invalid_partial.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/invalid_partial.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid.xml index 555722e21f410..02c57ce5259d9 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid.xml @@ -1,7 +1,7 @@ @@ -98,4 +98,4 @@ 0 10 - \ No newline at end of file + diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid_partial.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid_partial.xml index b531494906e02..811785310fe7a 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid_partial.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/request/valid_partial.xml @@ -1,7 +1,7 @@ @@ -68,4 +68,4 @@ 10 10 - \ No newline at end of file + diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/invalid.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/invalid.xml index 7bc394909165a..0c3c0fd863fbc 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/invalid.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/invalid.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/valid.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/valid.xml index b163f45bea5c7..c6d006b77f0f2 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/valid.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Search/_files/search_engine/valid.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/ConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/ConfigTest.php index deefc9aba3a3a..201de5608a791 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/ConfigTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/ConfigTest.php @@ -5,7 +5,7 @@ * Find "indexer.xml" files in code tree and validate them. Also verify schema fails on an invalid xml and * passes on a valid xml. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity\Magento\Indexer; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/invalid.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/invalid.xml index b91ad27413007..6dba8a48050d0 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/invalid.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/invalid.xml @@ -3,7 +3,7 @@ /** * This file contains errors that will fail schema validation. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid.xml index c5fd73f7b25d5..c8dd8ad01063c 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid_partial.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid_partial.xml index f5a341b289287..3a20c81dc4bb3 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid_partial.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Indexer/_files/valid_partial.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Config/ReferentialTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Config/ReferentialTest.php index 74ee4e5eeb77f..fa4196bf63271 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Config/ReferentialTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Config/ReferentialTest.php @@ -2,7 +2,7 @@ /** * Validates that payment groups referenced from store configuration matches the groups declared in payment.xml * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity\Magento\Payment\Config; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/ConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/ConfigTest.php index 7dbee705485e5..c7385c42ed669 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/ConfigTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/ConfigTest.php @@ -2,7 +2,7 @@ /** * Find "payment.xml" files and validate them * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity\Magento\Payment\Model; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment.xml index aa707e68bb403..2f7cbd10410bd 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment_partial.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment_partial.xml index b4462b8d8f62b..c1eccbff21f4c 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment_partial.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/invalid_payment_partial.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment.xml index c439e12434a10..969f5ce6abb53 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment_partial.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment_partial.xml index 456efdb3ec3ae..b80e698744aaf 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment_partial.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Payment/Model/_files/payment_partial.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/ConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/ConfigTest.php index 17e3f4e44b135..f5d1de340f966 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/ConfigTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/ConfigTest.php @@ -5,7 +5,7 @@ * Find "persistent.xml" files in code tree and validate them. Also verify schema fails on an invalid xml and * passes on a valid xml. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity\Magento\Persistent; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/invalid_persistent.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/invalid_persistent.xml index e698d6972ebe9..e3555f4391e06 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/invalid_persistent.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/invalid_persistent.xml @@ -5,7 +5,7 @@ * * The welcome and models nodes will be unexpected - this is the old version of persistent.xml. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/valid_persistent.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/valid_persistent.xml index 9ebe1e8bf6009..23d78fd6a91b9 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/valid_persistent.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Persistent/_files/valid_persistent.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/ConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/ConfigTest.php index d1d3f3b2f2c0e..fd8401d7189a5 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/ConfigTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/ConfigTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/_files/webapi.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/_files/webapi.xml index 9605858f32936..141bef254453c 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/_files/webapi.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Webapi/Model/_files/webapi.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/WidgetConfigTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/WidgetConfigTest.php index 30321c6e695e3..02cc7e43e8fd9 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/WidgetConfigTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/WidgetConfigTest.php @@ -2,7 +2,7 @@ /** * Find "widget.xml" files and validate them * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Test\Integrity\Magento\Widget; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/invalid_widget.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/invalid_widget.xml index c9eec21bc16ca..20f90ac424936 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/invalid_widget.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/invalid_widget.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget.xml index a6d85da8e13b7..176b25649a7b1 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget_file.xml b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget_file.xml index c809ee6346912..a7b0bf27b50cd 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget_file.xml +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Widget/_files/widget_file.xml @@ -1,7 +1,7 @@ @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ObserverImplementationTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ObserverImplementationTest.php index 037069e8fd2ca..61a2338c9672b 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ObserverImplementationTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ObserverImplementationTest.php @@ -1,6 +1,6 @@ fail('Copyright is missing or has wrong year in ' . $filename); } }, @@ -27,7 +27,7 @@ function ($filename) { public function copyrightDataProvider() { - $blackList = include __DIR__ . '/_files/copyright/blacklist.php'; + $blackList = $this->getFilesData('blacklist*.php'); $changedFiles = []; foreach (glob(__DIR__ . '/../_files/changed_files*') as $listFile) { @@ -56,4 +56,18 @@ function ($path) use ($blackList) { ); return $changedFiles; } + + /** + * @param string $filePattern + * @return array + */ + protected function getFilesData($filePattern) + { + $result = []; + foreach (glob(__DIR__ . '/_files/copyright/' . $filePattern) as $file) { + $fileData = include $file; + $result = array_merge($result, $fileData); + } + return $result; + } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/EmailTemplateTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/EmailTemplateTest.php index 85b87a24a55ef..62c0340f7a403 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/EmailTemplateTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/EmailTemplateTest.php @@ -1,6 +1,6 @@ assertEmpty( - reset($matches), - 'module.xml changes for patch releases in non-actual branches are not allowed:' . PHP_EOL . - implode(PHP_EOL, array_values(reset($matches))) - ); + if (!self::$actualBranch) { + preg_match_all('|etc/module\.xml$|mi', self::$changedFileList, $matches); + $this->assertEmpty( + reset($matches), + 'module.xml changes for patch releases in non-actual branches are not allowed:' . PHP_EOL . + implode(PHP_EOL, array_values(reset($matches))) + ); + } } /** @@ -50,11 +80,13 @@ public function testModuleXmlFiles() */ public function testModuleSetupFiles() { - preg_match_all('|app/code/Magento/[^/]+/Setup/[^/]+$|mi', self::$changedFileList, $matches); - $this->assertEmpty( - reset($matches), - 'Code with changes for DB schema or data in non-actual branches are not allowed:' . PHP_EOL . - implode(PHP_EOL, array_values(reset($matches))) - ); + if (!self::$actualBranch) { + preg_match_all('|app/code/Magento/[^/]+/Setup/[^/]+$|mi', self::$changedFileList, $matches); + $this->assertEmpty( + reset($matches), + 'Code with changes for DB schema or data in non-actual branches are not allowed:' . PHP_EOL . + implode(PHP_EOL, array_values(reset($matches))) + ); + } } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteAclTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteAclTest.php index 27fb56346efcc..26a834bdcac2d 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteAclTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteAclTest.php @@ -1,6 +1,6 @@ _assertNotRegExp( '/[^a-z\d_]' . preg_quote($class, '/') . '[^a-z\d_\\\\]/iS', $content, diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteConnectionTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteConnectionTest.php index d900c7f535169..765b28b7e9bd5 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteConnectionTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteConnectionTest.php @@ -1,6 +1,6 @@ componentRegistrar = new ComponentRegistrar(); + } /** * Read fixtures into memory as arrays + * * @return void */ public static function setUpBeforeClass() @@ -69,6 +80,7 @@ protected static function _readList($file) /** * Test that restricted entities are not used in PHP files + * * @return void */ public function testPhpFiles() @@ -97,15 +109,13 @@ function ($file) { protected function _testRestrictedClasses($file) { $content = file_get_contents($file); - $componentRegistrar = new ComponentRegistrar(); foreach (self::$_classes as $restrictedClass => $classRules) { foreach ($classRules['exclude'] as $skippedPathInfo) { - $skippedPath = $componentRegistrar->getPath($skippedPathInfo['type'], $skippedPathInfo['name']) - . '/' . $skippedPathInfo['path']; - if (strpos($file, $skippedPath) === 0) { + if (strpos($file, $this->getExcludedFilePath($skippedPathInfo)) === 0) { continue 2; } } + $this->assertFalse( \Magento\TestFramework\Utility\CodeCheck::isClassUsed($restrictedClass, $content), sprintf( @@ -117,4 +127,18 @@ protected function _testRestrictedClasses($file) ); } } + + /** + * Get full path for excluded file + * + * @param array $pathInfo + * @return string + */ + private function getExcludedFilePath($pathInfo) + { + if ($pathInfo['type'] != 'setup') { + return $this->componentRegistrar->getPath($pathInfo['type'], $pathInfo['name']) . '/' . $pathInfo['path']; + } + return BP . '/setup/' . $pathInfo['path']; + } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/TableTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/TableTest.php index 6406b1e777be0..b522cdf120635 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/TableTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/TableTest.php @@ -1,6 +1,6 @@ $value) { + $excludes = $value['exclude']; + $excludePaths = []; + foreach ($excludes as $exclude) { + if ('setup' == $exclude['type']) { + $excludePaths[] = BP . '/setup/' . $exclude['path']; + } else { + $excludePaths[] = $componentRegistrar->getPath($exclude['type'], $exclude['name']) + . '/' . $exclude['path']; + } + } + $data[$key]['exclude'] = $excludePaths; + } + } + + /** + * Isolate including a file into a method to reduce scope + * + * @param string $file + * @return array + */ + private static function readList($file) + { + return include $file; + } + + /** + * Detect unsecure functions usage for changed files in whitelist with the exception of blacklist + * + * @return void + */ + public function testUnsecureFunctionsUsage() + { + $invoker = new \Magento\Framework\App\Utility\AggregateInvoker($this); + $functionDetector = new FunctionDetector(); + $invoker( + function ($fileFullPath) use ($functionDetector) { + $functions = $this->getFunctions($fileFullPath); + $lines = $functionDetector->detect($fileFullPath, array_keys($functions)); + + $message = ''; + if (!empty($lines)) { + $message = $this->composeMessage($fileFullPath, $lines, $functions); + } + $this->assertEmpty( + $lines, + $message + ); + }, + $this->getFilesToVerify() + ); + } + + /** + * Compose message + * + * @param string $fileFullPath + * @param array $lines + * @param array $functionRules + * @return string + */ + private function composeMessage($fileFullPath, $lines, $functionRules) + { + $result = ''; + foreach ($lines as $lineNumber => $detectedFunctions) { + $detectedFunctionRules = array_intersect_key($functionRules, array_flip($detectedFunctions)); + $replacementString = ''; + foreach ($detectedFunctionRules as $function => $functionRule) { + $replacement = $functionRule['replacement']; + if (is_array($replacement)) { + $replacement = array_unique($replacement); + $replacement = count($replacement) > 1 ? + "[\n\t\t\t" . implode("\n\t\t\t", $replacement) . "\n\t\t]" : + $replacement[0]; + } + $replacement = empty($replacement) ? 'No suggested replacement at this time' : $replacement; + $replacementString .= "\t\t'$function' => '$replacement'\n"; + } + $result .= sprintf( + "Functions '%s' are not secure in %s. \n\tSuggested replacement:\n%s", + implode(', ', $detectedFunctions), + $fileFullPath . ':' . $lineNumber, + $replacementString + ); + } + return $result; + } + + /** + * Get files to be verified + * + * @return array + */ + private function getFilesToVerify() + { + $fileExtensions = $this->fileExtensions; + $directoriesToScan = Files::init()->readLists(__DIR__ . '/_files/security/whitelist.txt'); + + $filesToVerify = []; + foreach (glob(__DIR__ . '/../_files/changed_files*') as $listFile) { + $filesToVerify = array_merge( + $filesToVerify, + file($listFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) + ); + } + array_walk( + $filesToVerify, + function (&$file) { + $file = [BP . '/' . $file]; + } + ); + $filesToVerify = array_filter( + $filesToVerify, + function ($path) use ($directoriesToScan, $fileExtensions) { + if (!file_exists($path[0])) { + return false; + } + $path = realpath($path[0]); + foreach ($directoriesToScan as $directory) { + $directory = realpath($directory); + if (strpos($path, $directory) === 0) { + if (preg_match($fileExtensions, $path)) { + // skip unit tests + if (preg_match('#' . preg_quote('Test/Unit', '#') . '#', $path)) { + return false; + } + return true; + } + } + } + return false; + } + ); + return $filesToVerify; + } + + /** + * Get functions for the given file + * + * @param string $fileFullPath + * @return array + */ + private function getFunctions($fileFullPath) + { + $fileExtension = pathinfo($fileFullPath, PATHINFO_EXTENSION); + $functions = []; + if ($fileExtension == 'php') { + $functions = self::$phpUnsecureFunctions; + } elseif ($fileExtension == 'js') { + $functions = self::$jsUnsecureFunctions; + } elseif ($fileExtension == 'phtml') { + $functions = array_merge_recursive(self::$phpUnsecureFunctions, self::$jsUnsecureFunctions); + } + foreach ($functions as $function => $functionRules) { + if (in_array($fileFullPath, $functionRules['exclude'])) { + unset($functions[$function]); + } + } + return $functions; + } +} diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/WordsTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/WordsTest.php index 635078ace6ca8..c4405994592e9 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/WordsTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/WordsTest.php @@ -1,6 +1,6 @@ [, ]) * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ return [ @@ -785,6 +785,7 @@ ['Mage_Core_Model_Config_Fieldset', 'Magento\Core\Model\Fieldset\Config'], ['Mage_Core_Model_Config_Options', 'Magento\Framework\Filesystem'], ['Magento\Framework\App\Dir', 'Magento\Framework\Filesystem'], + ['Magento\Framework\EntityManager\CustomAttributesMapper'], ['Magento\Framework\Filesystem\Adapter\Local', 'Magento\Framework\Filesystem\Driver\File'], ['Magento\Framework\Filesystem\Adapter\Zlib', 'Magento\Framework\Filesystem\Driver\Zlib'], ['Magento\Framework\Filesystem\AdapterInterface'], @@ -3825,8 +3826,8 @@ ], ['Magento\Setup\Model\Deployer', 'Magento\Deploy\Model\Deployer'], [ - 'Magento\Setup\Console\Command\DeployStaticContentCommand', - 'Magento\Deploy\Console\Command\DeployStaticContentCommand' + 'Magento\Deploy\Console\Command\DeployStaticContentCommand', + 'Magento\Setup\Console\Command\DeployStaticContentCommand' ], [ 'Magento\Setup\Test\Unit\Console\Command\DeployStaticContentCommandTest', diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php index e064965473ce5..65a631ba5c60f 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_config_nodes.php @@ -4,7 +4,7 @@ * * Format: => * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php index 491f02c8e0752..a67ec4a78c68f 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php @@ -4,7 +4,7 @@ * * Format: array([, = ''[, ]]) * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -562,10 +562,13 @@ '\Magento\Framework\App\Filesystem', '\Magento\Framework\App\Filesystem\DirectoryList::SESSION', ], - ['DI_DIR', '\Magento\Framework\App\Filesystem', '\Magento\Framework\App\Filesystem\DirectoryList::DI'], + ['DI_DIR', + '\Magento\Framework\App\Filesystem', + '\Magento\Framework\App\Filesystem\DirectoryList::GENERATED_METADATA' + ], ['GENERATION_DIR', '\Magento\Framework\App\Filesystem', - '\Magento\Framework\App\Filesystem\DirectoryList::GENERATION', + '\Magento\Framework\App\Filesystem\DirectoryList::GENERATED_CODE', ], ['UPLOAD_DIR', '\Magento\Framework\App\Filesystem', diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php index bc49ab15a7d54..20cf93e55b8c6 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php @@ -2,7 +2,7 @@ /** * Obsolete methods * Format: array([, = ''[, [, ]]]) - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -2155,7 +2155,6 @@ ['addOrderedQty', 'Magento\Reports\Model\ResourceModel\Product\Collection'], ['prepareForProductsInCarts', 'Magento\Reports\Model\ResourceModel\Quote\Collection'], ['getOrdersSubSelect', 'Magento\Reports\Model\ResourceModel\Quote\Collection'], - ['isOrderIncrementIdUsed', 'Magento\Quote\Model\ResourceModel\Quote'], ['isStateProtected', 'Magento\Sales\Model\Order'], ['_getBundleOptions', 'Magento\Bundle\Block\Checkout\Cart\Item\Renderer'], ['_getSelectionFinalPrice', 'Magento\Bundle\Block\Checkout\Cart\Item\Renderer'], diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php index 9dd8ad6c6d5dd..e6901cc6a27ef 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php @@ -4,7 +4,7 @@ * * Format: array([, ]) * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ return [ diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_paths.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_paths.php index 0eaf08b63298e..9621625f75f74 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_paths.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_paths.php @@ -4,7 +4,7 @@ * * Format: array([, ]) * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ return [ diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php index 421ba4f1498b2..640a02955d3d4 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_properties.php @@ -4,7 +4,7 @@ * * Format: array([, = ''[, ]]) * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/response/blacklist/files_list.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/response/blacklist/files_list.php index c93b7f009285c..33611a02b3341 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/response/blacklist/files_list.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/response/blacklist/files_list.php @@ -1,6 +1,6 @@ will be suggested to be used instead. * Use to specify files and directories that are allowed to use restricted classes. * * Format: array(, [, array()]]) - * - * Copyright © 2016 Magento. All rights reserved. - * See COPYING.txt for license details. */ return [ 'Zend_Db_Select' => [ 'replacement' => '\Magento\Framework\DB\Select', 'exclude' => [ - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Select.php'], - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'Model/ResourceModel/Iterator.php'], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Select.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Adapter/Pdo/Mysql.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Model/ResourceModel/Iterator.php' + ], ] ], 'Zend_Db_Adapter_Pdo_Mysql' => [ 'replacement' => '\Magento\Framework\DB\Adapter\Pdo\Mysql', 'exclude' => [ - ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Adapter/Pdo/Mysql.php' + ], ] ], + 'Magento\Framework\Serialize\Serializer\Serialize' => [ + 'replacement' => 'Magento\Framework\Serialize\SerializerInterface', + 'exclude' => [ + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/ObjectManager/ConfigLoader/Compiled.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/Config/ScopePool.php'], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/ObjectManager/ConfigCache.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/ObjectManager/ConfigLoader.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Adapter/Pdo/Mysql.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/DataConverter/SerializedToJson.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'DB/Test/Unit/DataConverter/SerializedToJsonTest.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'ObjectManager/Config/Compiled.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Interception/Config/Config.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Interception/PluginList/PluginList.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'App/Router/ActionList.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Serialize/Test/Unit/Serializer/SerializeTest.php' + ], + [ + 'type' => 'setup', + 'path' => 'src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_Sales', + 'path' => 'Setup/SerializedDataConverter.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_Sales', + 'path' => 'Test/Unit/Setup/SerializedDataConverterTest.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Flag.php' + ] + ] + ], + 'ArrayObject' => [ + 'replacement' => 'Custom class, extended from ArrayObject with overwritten serialize/unserialize methods', + 'exclude' => [ + [ + 'type' => 'module', + 'name' => 'Magento_Theme', + 'path' => 'Model/Indexer/Design/Config.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_Ui', + 'path' => 'Model/Manager.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_Ui', + 'path' => 'Test/Unit/Model/ManagerTest.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_Backend', + 'path' => 'Model/Menu.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_CatalogSearch', + 'path' => 'Model/Indexer/Fulltext.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_CatalogSearch', + 'path' => 'Test/Unit/Model/Indexer/FulltextTest.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_CatalogSearch', + 'path' => 'Model/Indexer/Fulltext.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Test/Unit/FlagTest.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Validator/Test/Unit/Constraint/PropertyTest.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Indexer/Test/Unit/BatchTest.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'View/Element/UiComponent/ArrayObjectFactory.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'View/Element/UiComponent/Config/Provider/Component/Definition.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'Indexer/Action/Base.php' + ] + ] + ], + 'Magento\Framework\View\Element\UiComponent\ArrayObjectFactory' => [ + 'replacement' => 'Factory that creates custom class, extended from ArrayObject with overwritten ' + . 'serialize/unserialize methods', + 'exclude' => [ + [ + 'type' => 'module', + 'name' => 'Magento_Ui', + 'path' => 'Model/Manager.php' + ], + [ + 'type' => 'module', + 'name' => 'Magento_Ui', + 'path' => 'Test/Unit/Model/ManagerTest.php' + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'View/Element/UiComponent/Config/Provider/Component/Definition.php' + ] + ] + ] ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php new file mode 100644 index 0000000000000..3611c189a7002 --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php @@ -0,0 +1,52 @@ + will be suggested to be used instead. + * Use to specify files and directories that are allowed to use function. + * + * Format: [ + * => [ + * 'replacement' => , + * 'exclude' => [ + * , + * , + * ] + * ] + */ +return [ + 'unserialize' => [ + 'replacement' => '\Magento\Framework\Serialize\SerializerInterface::unserialize', + 'exclude' => [ + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'Serialize/Serializer/Serialize.php'], + ] + ], + 'serialize' => [ + 'replacement' => '\Magento\Framework\Serialize\SerializerInterface::serialize', + 'exclude' => [ + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'DB/Adapter/Pdo/Mysql.php'], + ['type' => 'library', 'name' => 'magento/framework', 'path' => 'Serialize/Serializer/Serialize.php'], + ] + ], + 'eval' => [ + 'replacement' => '', + 'exclude' => [] + ], + 'md5' => [ + 'replacement' => '', + 'exclude' => [] + ], + 'srand' => [ + 'replacement' => '', + 'exclude' => [] + ], + 'mt_srand' => [ + 'replacement' => '', + 'exclude' => [] + ], +]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/whitelist.txt b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/whitelist.txt new file mode 100644 index 0000000000000..e464d9713657f --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/whitelist.txt @@ -0,0 +1,5 @@ +# "Component Type" "Component Name" "Path Pattern" +module * / +library * / +setup +pub diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml index 22c9b202e3c5c..ace49940c5628 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php index a31bc279fc92f..e58226347deac 100644 --- a/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Less/LiveCodeTest.php @@ -1,6 +1,6 @@ @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php index 68fac7bf5f372..2d968602b6fa8 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php @@ -1,6 +1,6 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml index 4b592d8646a8d..bb17510603d16 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpmd/ruleset.xml @@ -1,7 +1,7 @@ diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/exempt_modules/ce.php b/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/exempt_modules/ce.php index 077bc4138d199..5ef7a8a1fb3e5 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/exempt_modules/ce.php +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/whitelist/exempt_modules/ce.php @@ -1,6 +1,6 @@ @@ -52,4 +52,4 @@ coverage_crap4j_placeholder--> - \ No newline at end of file + diff --git a/dev/tools/Magento/Tools/Layout/processors/addItemRenderer.xsl b/dev/tools/Magento/Tools/Layout/processors/addItemRenderer.xsl index 14852ef4025cd..5787399fe3565 100644 --- a/dev/tools/Magento/Tools/Layout/processors/addItemRenderer.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/addItemRenderer.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/addToParentGroup.xsl b/dev/tools/Magento/Tools/Layout/processors/addToParentGroup.xsl index 7c0b64e849a6d..413bda2432ddb 100644 --- a/dev/tools/Magento/Tools/Layout/processors/addToParentGroup.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/addToParentGroup.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/headBlocks.xsl b/dev/tools/Magento/Tools/Layout/processors/headBlocks.xsl index 8171706704ac6..158706bea326b 100644 --- a/dev/tools/Magento/Tools/Layout/processors/headBlocks.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/headBlocks.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutArguments.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutArguments.xsl index f73e5c3cb48b0..14c2c61c61bd3 100644 --- a/dev/tools/Magento/Tools/Layout/processors/layoutArguments.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/layoutArguments.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutGridContainer.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutGridContainer.xsl index 333f084f38c4b..95985c3aae689 100644 --- a/dev/tools/Magento/Tools/Layout/processors/layoutGridContainer.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/layoutGridContainer.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutHandles.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutHandles.xsl index 9fb9b0bb3c95d..f9002e2ca819c 100644 --- a/dev/tools/Magento/Tools/Layout/processors/layoutHandles.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/layoutHandles.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutLabels.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutLabels.xsl index 1c8d7aa3d0a2d..7c86130406779 100644 --- a/dev/tools/Magento/Tools/Layout/processors/layoutLabels.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/layoutLabels.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutReferences.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutReferences.xsl index 577dbbbafd496..b0d2fc5b06329 100644 --- a/dev/tools/Magento/Tools/Layout/processors/layoutReferences.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/layoutReferences.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/Magento/Tools/Layout/processors/layoutTranslate.xsl b/dev/tools/Magento/Tools/Layout/processors/layoutTranslate.xsl index f793d42ac4245..aff4607b2cb87 100644 --- a/dev/tools/Magento/Tools/Layout/processors/layoutTranslate.xsl +++ b/dev/tools/Magento/Tools/Layout/processors/layoutTranslate.xsl @@ -1,6 +1,6 @@ diff --git a/dev/tools/bootstrap.php b/dev/tools/bootstrap.php index 11941dd7ffee4..3336124de0fd4 100644 --- a/dev/tools/bootstrap.php +++ b/dev/tools/bootstrap.php @@ -1,6 +1,6 @@ /cache/**/*", "<%= combo.autopath(\""+name+"\", path.pub ) %>**/*", "<%= combo.autopath(\""+name+"\", path.tmpLess) %>**/*", - "<%= combo.autopath(\""+name+"\", path.tmpSource) %>**/*" + "<%= combo.autopath(\""+name+"\", path.tmpSource) %>**/*", + "<%= path.deployedVersion %>" ] } ] @@ -56,7 +57,8 @@ var cleanOptions = { "dot": true, "src": [ "<%= path.pub %>frontend/**/*", - "<%= path.pub %>adminhtml/**/*" + "<%= path.pub %>adminhtml/**/*", + "<%= path.deployedVersion %>" ] } ] @@ -73,7 +75,8 @@ var cleanOptions = { "<%= path.pub %>frontend/**/*.less", "<%= path.pub %>frontend/**/*.css", "<%= path.pub %>adminhtml/**/*.less", - "<%= path.pub %>adminhtml/**/*.css" + "<%= path.pub %>adminhtml/**/*.css", + "<%= path.deployedVersion %>" ] } ] @@ -102,7 +105,8 @@ var cleanOptions = { "src": [ "<%= path.pub %>**/*.js", "<%= path.pub %>**/*.html", - "<%= path.pub %>_requirejs/**/*" + "<%= path.pub %>_requirejs/**/*", + "<%= path.deployedVersion %>" ] } ] diff --git a/dev/tools/grunt/configs/combo.js b/dev/tools/grunt/configs/combo.js index 6dcbe7e36a667..87bc55eacfbda 100644 --- a/dev/tools/grunt/configs/combo.js +++ b/dev/tools/grunt/configs/combo.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/configs/eslint.js b/dev/tools/grunt/configs/eslint.js index 3bb01cc09f080..6b342dd80f531 100644 --- a/dev/tools/grunt/configs/eslint.js +++ b/dev/tools/grunt/configs/eslint.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/configs/exec.js b/dev/tools/grunt/configs/exec.js index 3e675ff9b5d81..d91d3b59e349e 100644 --- a/dev/tools/grunt/configs/exec.js +++ b/dev/tools/grunt/configs/exec.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/configs/imagemin.js b/dev/tools/grunt/configs/imagemin.js index a2de03be200de..9eb6686941462 100644 --- a/dev/tools/grunt/configs/imagemin.js +++ b/dev/tools/grunt/configs/imagemin.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/configs/jscs.js b/dev/tools/grunt/configs/jscs.js index a42206d020a16..e0564adaa555a 100644 --- a/dev/tools/grunt/configs/jscs.js +++ b/dev/tools/grunt/configs/jscs.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/configs/less.js b/dev/tools/grunt/configs/less.js index 7a84957712740..7c7897e1f7768 100644 --- a/dev/tools/grunt/configs/less.js +++ b/dev/tools/grunt/configs/less.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/configs/path.js b/dev/tools/grunt/configs/path.js index 03621998c14a6..c73f48839a6d7 100644 --- a/dev/tools/grunt/configs/path.js +++ b/dev/tools/grunt/configs/path.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -13,6 +13,7 @@ module.exports = { tmpLess: 'var/view_preprocessed/less/', tmpSource: 'var/view_preprocessed/source/', tmp: 'var', + deployedVersion: 'pub/static/deployed_version.txt', css: { setup: 'setup/pub/styles', updater: '../magento2-updater/pub/css' diff --git a/dev/tools/grunt/configs/replace.js b/dev/tools/grunt/configs/replace.js index 38d65179e4675..ea3f45257501f 100644 --- a/dev/tools/grunt/configs/replace.js +++ b/dev/tools/grunt/configs/replace.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -10,7 +10,7 @@ var nlWin = '\r\n', function findCopyright(lang, nlSys) { var copyrightText = { - firstLine: 'Copyright © 2016 Magento. All rights reserved.', + firstLine: 'Copyright © 2013-2017 Magento, Inc. All rights reserved.', secondLine: 'See COPYING.txt for license details.' }; switch (lang) { diff --git a/dev/tools/grunt/configs/themes.js b/dev/tools/grunt/configs/themes.js index a4d34c50fb823..604847e419d0d 100644 --- a/dev/tools/grunt/configs/themes.js +++ b/dev/tools/grunt/configs/themes.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/configs/usebanner.js b/dev/tools/grunt/configs/usebanner.js index 365a7d81a2bf9..3f2bf3e8e24e2 100644 --- a/dev/tools/grunt/configs/usebanner.js +++ b/dev/tools/grunt/configs/usebanner.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -7,7 +7,7 @@ function printCopyright(lang) { var copyrightText = { - firstLine: 'Copyright © 2016 Magento. All rights reserved.', + firstLine: 'Copyright © 2013-2017 Magento, Inc. All rights reserved.', secondLine: 'See COPYING.txt for license details.' }, nlWin = '\r\n'; diff --git a/dev/tools/grunt/configs/watch.js b/dev/tools/grunt/configs/watch.js index 84657ae7c4d80..061078ccba158 100644 --- a/dev/tools/grunt/configs/watch.js +++ b/dev/tools/grunt/configs/watch.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/tasks/black-list-generator.js b/dev/tools/grunt/tasks/black-list-generator.js index 9dcf0e25fd8e5..d7b067ec5dba6 100644 --- a/dev/tools/grunt/tasks/black-list-generator.js +++ b/dev/tools/grunt/tasks/black-list-generator.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -23,4 +23,4 @@ module.exports = function (grunt) { fst.write(blacklistFile, data); }); }); -}; \ No newline at end of file +}; diff --git a/dev/tools/grunt/tasks/clean-black-list.js b/dev/tools/grunt/tasks/clean-black-list.js index 9ca0dfa57e60d..97fbb2d922ab2 100644 --- a/dev/tools/grunt/tasks/clean-black-list.js +++ b/dev/tools/grunt/tasks/clean-black-list.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/tasks/deploy.js b/dev/tools/grunt/tasks/deploy.js index a64db7f8576be..01bb28f0510ac 100644 --- a/dev/tools/grunt/tasks/deploy.js +++ b/dev/tools/grunt/tasks/deploy.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ module.exports = function (grunt) { diff --git a/dev/tools/grunt/tasks/mage-minify.js b/dev/tools/grunt/tasks/mage-minify.js index c7bb159d7770e..b337973975a58 100644 --- a/dev/tools/grunt/tasks/mage-minify.js +++ b/dev/tools/grunt/tasks/mage-minify.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ module.exports = function (grunt) { diff --git a/dev/tools/grunt/tasks/static.js b/dev/tools/grunt/tasks/static.js index d288fae2f445f..858ef9ca82316 100644 --- a/dev/tools/grunt/tasks/static.js +++ b/dev/tools/grunt/tasks/static.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/tools/collect-validation-files.js b/dev/tools/grunt/tools/collect-validation-files.js index a1dd7989c4f52..29974ec84fdd3 100644 --- a/dev/tools/grunt/tools/collect-validation-files.js +++ b/dev/tools/grunt/tools/collect-validation-files.js @@ -1,10 +1,10 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ 'use strict'; diff --git a/dev/tools/grunt/tools/files-router.js b/dev/tools/grunt/tools/files-router.js index 2bf6f9d8cc2e9..81710f2a520c7 100644 --- a/dev/tools/grunt/tools/files-router.js +++ b/dev/tools/grunt/tools/files-router.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/dev/tools/grunt/tools/fs-tools.js b/dev/tools/grunt/tools/fs-tools.js index 7e7a1335958ae..f2806a4af9803 100644 --- a/dev/tools/grunt/tools/fs-tools.js +++ b/dev/tools/grunt/tools/fs-tools.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ 'use strict'; diff --git a/dev/travis/before_install.sh b/dev/travis/before_install.sh index 568cdb495b386..8bf47ae1beb41 100755 --- a/dev/travis/before_install.sh +++ b/dev/travis/before_install.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright © 2016 Magento. All rights reserved. +# Copyright © 2013-2017 Magento, Inc. All rights reserved. # See COPYING.txt for license details. set -e diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index 644d08d097e49..4d8d5d1246adf 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Copyright © 2016 Magento. All rights reserved. +# Copyright © 2013-2017 Magento, Inc. All rights reserved. # See COPYING.txt for license details. set -e @@ -12,9 +12,13 @@ case $TEST_SUITE in cd dev/tests/integration test_set_list=$(find testsuite/* -maxdepth 1 -mindepth 1 -type d | sort) - test_set_size=$(($(printf "$test_set_list" | wc -l)/INTEGRATION_SETS)) + test_set_count=$(printf "$test_set_list" | wc -l) + test_set_size[1]=$(printf "%.0f" $(echo "$test_set_count*0.12" | bc)) #12% + test_set_size[2]=$(printf "%.0f" $(echo "$test_set_count*0.32" | bc)) #32% + test_set_size[3]=$((test_set_count-test_set_size[1]-test_set_size[2])) #56% + echo "Total = ${test_set_count}; Batch #1 = ${test_set_size[1]}; Batch #2 = ${test_set_size[2]}; Batch #3 = ${test_set_size[3]};"; - echo "==> preparing integration testsuite on index $INTEGRATION_INDEX with set size of $test_set_size" + echo "==> preparing integration testsuite on index $INTEGRATION_INDEX with set size of ${test_set_size[$INTEGRATION_INDEX]}" cp phpunit.xml.dist phpunit.xml # remove memory usage tests if from any set other than the first @@ -24,20 +28,23 @@ case $TEST_SUITE in fi # divide test sets up by indexed testsuites - i=0; j=1 + i=0; j=1; dirIndex=1; testIndex=1; for test_set in $test_set_list; do test_xml[j]+=" $test_set\n" if [[ $j -eq $INTEGRATION_INDEX ]]; then - echo " + including $test_set" + echo "$dirIndex: Batch #$j($testIndex of ${test_set_size[$j]}): + including $test_set" else - echo " - excluding $test_set" + echo "$dirIndex: Batch #$j($testIndex of ${test_set_size[$j]}): + excluding $test_set" fi + testIndex=$((testIndex+1)) + dirIndex=$((dirIndex+1)) i=$((i+1)) - if [ $i -eq $test_set_size ] && [ $j -lt $INTEGRATION_SETS ]; then + if [ $i -eq ${test_set_size[$j]} ] && [ $j -lt $INTEGRATION_SETS ]; then j=$((j+1)) i=0 + testIndex=1 fi done diff --git a/generated/.htaccess b/generated/.htaccess new file mode 100644 index 0000000000000..896fbc5a341ea --- /dev/null +++ b/generated/.htaccess @@ -0,0 +1,2 @@ +Order deny,allow +Deny from all \ No newline at end of file diff --git a/index.php b/index.php index e74879ad90e83..81e6f89f2fc46 100644 --- a/index.php +++ b/index.php @@ -14,7 +14,7 @@ * $bootstrap->run($app); * -------------------------------------------- * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Acl.php b/lib/internal/Magento/Framework/Acl.php index ff4d65936fd0d..e17033c764740 100644 --- a/lib/internal/Magento/Framework/Acl.php +++ b/lib/internal/Magento/Framework/Acl.php @@ -2,7 +2,7 @@ /** * ACL. Can be queried for relations between roles and resources. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework; diff --git a/lib/internal/Magento/Framework/Acl/AclResource.php b/lib/internal/Magento/Framework/Acl/AclResource.php index 93fb1a6fa18f4..1e5336db9086f 100644 --- a/lib/internal/Magento/Framework/Acl/AclResource.php +++ b/lib/internal/Magento/Framework/Acl/AclResource.php @@ -1,6 +1,6 @@ _configReader = $configReader; $this->_resourceTreeBuilder = $resourceTreeBuilder; + $this->aclDataCache = $aclDataCache ?: ObjectManager::getInstance()->get( + \Magento\Framework\Config\CacheInterface::class + ); + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->cacheKey = $cacheKey; } /** @@ -35,9 +69,15 @@ public function __construct(\Magento\Framework\Config\ReaderInterface $configRea */ public function getAclResources() { + $tree = $this->aclDataCache->load($this->cacheKey); + if ($tree) { + return $this->serializer->unserialize($tree); + } $aclResourceConfig = $this->_configReader->read(); if (!empty($aclResourceConfig['config']['acl']['resources'])) { - return $this->_resourceTreeBuilder->build($aclResourceConfig['config']['acl']['resources']); + $tree = $this->_resourceTreeBuilder->build($aclResourceConfig['config']['acl']['resources']); + $this->aclDataCache->save($this->serializer->serialize($tree), $this->cacheKey); + return $tree; } return []; } diff --git a/lib/internal/Magento/Framework/Acl/AclResource/ProviderInterface.php b/lib/internal/Magento/Framework/Acl/AclResource/ProviderInterface.php index 747471d406702..561376007432d 100644 --- a/lib/internal/Magento/Framework/Acl/AclResource/ProviderInterface.php +++ b/lib/internal/Magento/Framework/Acl/AclResource/ProviderInterface.php @@ -1,6 +1,6 @@ _acl instanceof \Magento\Framework\Acl) { + return $this->_acl; + } + try { - if ($this->_cache->has()) { - $this->_acl = $this->_cache->get(); - } else { - $this->_acl = $this->_aclFactory->create(); - foreach ($this->_loaderPool as $loader) { - $loader->populateAcl($this->_acl); - } - $this->_cache->save($this->_acl); + $this->_acl = $this->_aclFactory->create(); + foreach ($this->_loaderPool as $loader) { + $loader->populateAcl($this->_acl); } } catch (\Exception $e) { throw new \LogicException('Could not create an acl object: ' . $e->getMessage()); @@ -80,4 +80,15 @@ public function getAcl() return $this->_acl; } + + /** + * Remove cached ACL instance. + * + * @return $this + */ + public function resetRuntimeAcl() + { + $this->_acl = null; + return $this; + } } diff --git a/lib/internal/Magento/Framework/Acl/Cache.php b/lib/internal/Magento/Framework/Acl/Cache.php index c9ea9e67bfc1d..af1c2928111d2 100644 --- a/lib/internal/Magento/Framework/Acl/Cache.php +++ b/lib/internal/Magento/Framework/Acl/Cache.php @@ -2,11 +2,17 @@ /** * ACL cache * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Acl; +/** + * Class Cache + * @package Magento\Framework\Acl + * @deprecated due to elimination of native PHP unserialization usage in 2.2. + * Use data cache \Magento\Framework\Acl\Data\CacheInterface instead. + */ class Cache implements CacheInterface { /** diff --git a/lib/internal/Magento/Framework/Acl/CacheInterface.php b/lib/internal/Magento/Framework/Acl/CacheInterface.php index 13b88d0662bda..40fcbc043f8f2 100644 --- a/lib/internal/Magento/Framework/Acl/CacheInterface.php +++ b/lib/internal/Magento/Framework/Acl/CacheInterface.php @@ -1,6 +1,6 @@ cache = $cache; + $this->aclBuilder = $aclBuilder; + $this->cacheTag = $cacheTag; + } + + /** + * {@inheritdoc} + */ + public function test($identifier) + { + return $this->cache->test($identifier); + } + + /** + * {@inheritdoc} + */ + public function load($identifier) + { + return $this->cache->load($identifier); + } + + /** + * {@inheritdoc} + */ + public function save($data, $identifier, array $tags = [], $lifeTime = null) + { + return $this->cache->save($data, $identifier, array_merge($tags, [$this->cacheTag]), $lifeTime); + } + + /** + * {@inheritdoc} + */ + public function remove($identifier) + { + return $this->cache->remove($identifier); + } + + /** + * {@inheritdoc} + */ + public function clean($mode = \Zend_Cache::CLEANING_MODE_MATCHING_TAG, array $tags = []) + { + $this->aclBuilder->resetRuntimeAcl(); + return $this->cache->clean($mode, array_merge($tags, [$this->cacheTag])); + } + + /** + * {@inheritdoc} + */ + public function getBackend() + { + return $this->cache->getBackend(); + } + + /** + * {@inheritdoc} + */ + public function getLowLevelFrontend() + { + return $this->cache->getLowLevelFrontend(); + } +} diff --git a/lib/internal/Magento/Framework/Acl/Data/CacheInterface.php b/lib/internal/Magento/Framework/Acl/Data/CacheInterface.php new file mode 100644 index 0000000000000..15e05e555e50e --- /dev/null +++ b/lib/internal/Magento/Framework/Acl/Data/CacheInterface.php @@ -0,0 +1,11 @@ + diff --git a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/MergedXsdTest.php b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/MergedXsdTest.php index 397f3211777ab..92d55531d1ff5 100644 --- a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/MergedXsdTest.php +++ b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/MergedXsdTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/_files/valid_merged_acl.xml b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/_files/valid_merged_acl.xml index c6139b9845e75..3c423920206a6 100644 --- a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/_files/valid_merged_acl.xml +++ b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/Config/_files/valid_merged_acl.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/ProviderTest.php b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/ProviderTest.php index 1d46d4eac48aa..7bdf57e6107bb 100644 --- a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/ProviderTest.php +++ b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/ProviderTest.php @@ -1,6 +1,6 @@ _configReaderMock = $this->getMock(\Magento\Framework\Config\ReaderInterface::class); @@ -32,9 +42,46 @@ protected function setUp() '', false ); + $this->serializerMock = $this->getMock( + \Magento\Framework\Serialize\Serializer\Json::class, + ['serialize', 'unserialize'], + [], + '', + false + ); + $this->serializerMock->expects($this->any()) + ->method('serialize') + ->will( + $this->returnCallback( + function ($value) { + return json_encode($value); + } + ) + ); + + $this->serializerMock->expects($this->any()) + ->method('unserialize') + ->will( + $this->returnCallback( + function ($value) { + return json_decode($value, true); + } + ) + ); + + $this->aclDataCacheMock = $this->getMock( + \Magento\Framework\Acl\Data\CacheInterface::class, + [], + [], + '', + false + ); + $this->_model = new \Magento\Framework\Acl\AclResource\Provider( $this->_configReaderMock, - $this->_treeBuilderMock + $this->_treeBuilderMock, + $this->aclDataCacheMock, + $this->serializerMock ); } @@ -43,6 +90,21 @@ public function testGetIfAclResourcesExist() $aclResourceConfig['config']['acl']['resources'] = ['ExpectedValue']; $this->_configReaderMock->expects($this->once())->method('read')->will($this->returnValue($aclResourceConfig)); $this->_treeBuilderMock->expects($this->once())->method('build')->will($this->returnValue('ExpectedResult')); + $this->aclDataCacheMock->expects($this->once())->method('save')->with( + json_encode('ExpectedResult'), + \Magento\Framework\Acl\AclResource\Provider::ACL_RESOURCES_CACHE_KEY + ); + $this->assertEquals('ExpectedResult', $this->_model->getAclResources()); + } + + public function testGetIfAclResourcesExistInCache() + { + $this->_configReaderMock->expects($this->never())->method('read'); + $this->_treeBuilderMock->expects($this->never())->method('build'); + $this->aclDataCacheMock->expects($this->once()) + ->method('load') + ->with(\Magento\Framework\Acl\AclResource\Provider::ACL_RESOURCES_CACHE_KEY) + ->will($this->returnValue(json_encode('ExpectedResult'))); $this->assertEquals('ExpectedResult', $this->_model->getAclResources()); } diff --git a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/TreeBuilderTest.php b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/TreeBuilderTest.php index 87c382dd5de55..c6f36d7b49121 100644 --- a/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/TreeBuilderTest.php +++ b/lib/internal/Magento/Framework/Acl/Test/Unit/AclResource/TreeBuilderTest.php @@ -1,6 +1,6 @@ _aclCacheMock->expects($this->at(1))->method('has')->will($this->returnValue(false)); - $this->_aclCacheMock->expects($this->at(2))->method('has')->will($this->returnValue(true)); - $this->_aclCacheMock->expects($this->once())->method('get')->will($this->returnValue($this->_aclMock)); - $this->_aclCacheMock->expects($this->exactly(1))->method('save')->with($this->_aclMock); + $this->_aclCacheMock->expects($this->never())->method('has'); + $this->_aclCacheMock->expects($this->never())->method('get'); + $this->_aclCacheMock->expects($this->never())->method('save'); + $this->_aclCacheMock->expects($this->never())->method('clean'); $this->_ruleLoader->expects($this->once())->method('populateAcl')->with($this->equalTo($this->_aclMock)); $this->_roleLoader->expects($this->once())->method('populateAcl')->with($this->equalTo($this->_aclMock)); @@ -73,14 +75,17 @@ public function testGetAclUsesLoadersProvidedInConfigurationToPopulateAclIfCache $this->_resourceLoader->expects($this->once())->method('populateAcl')->with($this->equalTo($this->_aclMock)); $this->assertEquals($this->_aclMock, $this->_model->getAcl()); - $this->assertEquals($this->_aclMock, $this->_model->getAcl()); } public function testGetAclReturnsAclStoredInCache() { - $this->_aclCacheMock->expects($this->exactly(2))->method('has')->will($this->returnValue(true)); - $this->_aclCacheMock->expects($this->exactly(2))->method('get')->will($this->returnValue($this->_aclMock)); + /** + * The acl cache of type \Magento\Framework\Acl\CacheInterface is deprecated and should never be called + */ + $this->_aclCacheMock->expects($this->never())->method('has'); + $this->_aclCacheMock->expects($this->never())->method('get'); $this->_aclCacheMock->expects($this->never())->method('save'); + $this->_aclCacheMock->expects($this->never())->method('clean'); $this->assertEquals($this->_aclMock, $this->_model->getAcl()); $this->assertEquals($this->_aclMock, $this->_model->getAcl()); } @@ -90,13 +95,18 @@ public function testGetAclReturnsAclStoredInCache() */ public function testGetAclRethrowsException() { - $this->_aclCacheMock->expects( + $this->_aclFactoryMock->expects( $this->once() )->method( - 'has' + 'create' )->will( $this->throwException(new \InvalidArgumentException()) ); $this->_model->getAcl(); } + + public function testResetRuntimeAcl() + { + $this->assertInstanceOf(Builder::class, $this->_model->resetRuntimeAcl()); + } } diff --git a/lib/internal/Magento/Framework/Acl/Test/Unit/CacheTest.php b/lib/internal/Magento/Framework/Acl/Test/Unit/CacheTest.php index d0c6515b1ce79..10bec1a45f06f 100644 --- a/lib/internal/Magento/Framework/Acl/Test/Unit/CacheTest.php +++ b/lib/internal/Magento/Framework/Acl/Test/Unit/CacheTest.php @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Acl/etc/acl_merged.xsd b/lib/internal/Magento/Framework/Acl/etc/acl_merged.xsd index f49d11b85ca9b..c5cada298aee9 100644 --- a/lib/internal/Magento/Framework/Acl/etc/acl_merged.xsd +++ b/lib/internal/Magento/Framework/Acl/etc/acl_merged.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/AclFactory.php b/lib/internal/Magento/Framework/AclFactory.php index 0e24bb9f997f0..62ac63a516a39 100644 --- a/lib/internal/Magento/Framework/AclFactory.php +++ b/lib/internal/Magento/Framework/AclFactory.php @@ -2,7 +2,7 @@ /** * Acl object factory. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework; diff --git a/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php b/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php index 4ef85a3ef5258..b9b6c58e31be3 100644 --- a/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php +++ b/lib/internal/Magento/Framework/Api/AbstractExtensibleObject.php @@ -1,6 +1,6 @@ setData(self::TOTAL_COUNT, $totalCount); } + + /** + * Retrieve ids of all items + * + * @return array + */ + public function getAllIds() + { + $ids = []; + foreach ($this->getItems() as $item) { + $ids[] = $item->getId(); + } + return $ids; + } } diff --git a/lib/internal/Magento/Framework/Api/Search/SearchResultFactory.php b/lib/internal/Magento/Framework/Api/Search/SearchResultFactory.php index 6b6714af2fac4..02b6bb9279edb 100644 --- a/lib/internal/Magento/Framework/Api/Search/SearchResultFactory.php +++ b/lib/internal/Magento/Framework/Api/Search/SearchResultFactory.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/ExtensionAttribute/Config/_files/extension_attributes_with_join_directives.xml b/lib/internal/Magento/Framework/Api/Test/Unit/ExtensionAttribute/Config/_files/extension_attributes_with_join_directives.xml index 1b9ebd42dc61a..d766fd42300fe 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/ExtensionAttribute/Config/_files/extension_attributes_with_join_directives.xml +++ b/lib/internal/Magento/Framework/Api/Test/Unit/ExtensionAttribute/Config/_files/extension_attributes_with_join_directives.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/Search/SearchResultTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/Search/SearchResultTest.php new file mode 100644 index 0000000000000..5459d00760217 --- /dev/null +++ b/lib/internal/Magento/Framework/Api/Test/Unit/Search/SearchResultTest.php @@ -0,0 +1,72 @@ +getMock(DocumentInterface::class); + $document2 = $this->getMock(DocumentInterface::class); + + $this->items = [ $document1, $document2]; + $document1->expects($this->any()) + ->method('getId') + ->willReturn(1); + $document2->expects($this->any()) + ->method('getId') + ->willReturn(2); + + $data = [ + 'items' => $this->items + ]; + $this->objectManager = new ObjectManager($this); + $this->search = $this->objectManager->getObject( + SearchResult::class, + [ + 'data' => $data + ] + ); + } + + /** + * Test getAllIds + */ + public function testGetAllIds() + { + $this->assertEquals([1, 2], $this->search->getAllIds()); + } + + /** + * Test getItems + */ + public function testGetItems() + { + $this->assertEquals($this->items, $this->search->getItems()); + } +} diff --git a/lib/internal/Magento/Framework/Api/Test/Unit/SearchCriteria/CollectionProcessor/FilterProcessorTest.php b/lib/internal/Magento/Framework/Api/Test/Unit/SearchCriteria/CollectionProcessor/FilterProcessorTest.php index d15e34774b303..0fc398b6f5ea9 100644 --- a/lib/internal/Magento/Framework/Api/Test/Unit/SearchCriteria/CollectionProcessor/FilterProcessorTest.php +++ b/lib/internal/Magento/Framework/Api/Test/Unit/SearchCriteria/CollectionProcessor/FilterProcessorTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Action/AbstractAction.php b/lib/internal/Magento/Framework/App/Action/AbstractAction.php index dab12da1597a2..e081c29def49e 100644 --- a/lib/internal/Magento/Framework/App/Action/AbstractAction.php +++ b/lib/internal/Magento/Framework/App/Action/AbstractAction.php @@ -2,7 +2,7 @@ /** * Abstract redirect/forward action class * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Action; diff --git a/lib/internal/Magento/Framework/App/Action/Action.php b/lib/internal/Magento/Framework/App/Action/Action.php index 82ecde1d95bf7..5500a4fd7aec2 100644 --- a/lib/internal/Magento/Framework/App/Action/Action.php +++ b/lib/internal/Magento/Framework/App/Action/Action.php @@ -1,6 +1,6 @@ cachePool = $cachePool; $this->cacheState = $cacheState; $this->cacheList = $cacheList; + $this->tagResolver = $tagResolver; } /** @@ -58,9 +66,9 @@ public function aroundSave( \Magento\Framework\Model\AbstractModel $object ) { $result = $proceed($object); - if ($object instanceof \Magento\Framework\DataObject\IdentityInterface) { - $this->cleanCacheByTags($object->getIdentities()); - } + $tags = $this->tagResolver->getTags($object); + $this->cleanCacheByTags($tags); + return $result; } @@ -78,10 +86,7 @@ public function aroundDelete( \Closure $proceed, \Magento\Framework\Model\AbstractModel $object ) { - $tags = []; - if ($object instanceof \Magento\Framework\DataObject\IdentityInterface) { - $tags = $object->getIdentities(); - } + $tags = $this->tagResolver->getTags($object); $result = $proceed($object); $this->cleanCacheByTags($tags); return $result; diff --git a/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php b/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php index 6a8b639f85364..3920ba73e858c 100644 --- a/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php +++ b/lib/internal/Magento/Framework/App/Cache/Frontend/Factory.php @@ -1,6 +1,6 @@ strategyFactory = $factory; + } + + /** + * Identify invalidation tags for the object using custom strategies + * + * @param object $object + * @throws \InvalidArgumentException + * @return array + */ + public function getTags($object) + { + if (!is_object($object)) { + throw new \InvalidArgumentException('Provided argument is not an object'); + } + + return $this->strategyFactory->getStrategy($object)->getTags($object); + } +} diff --git a/lib/internal/Magento/Framework/App/Cache/Tag/Strategy/Dummy.php b/lib/internal/Magento/Framework/App/Cache/Tag/Strategy/Dummy.php new file mode 100644 index 0000000000000..e94df2718f160 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Cache/Tag/Strategy/Dummy.php @@ -0,0 +1,26 @@ +customStrategies = $customStrategies; + $this->identifierStrategy = $identifierStrategy; + $this->dummyStrategy = $dummyStrategy; + } + + /** + * Return tag strategy for specified object + * + * @param object $object + * @throws \InvalidArgumentException + * @return \Magento\Framework\App\Cache\Tag\StrategyInterface + */ + public function getStrategy($object) + { + if (!is_object($object)) { + throw new \InvalidArgumentException('Provided argument is not an object'); + } + + $classHierarchy = array_merge( + [get_class($object) => get_class($object)], + class_parents($object), + class_implements($object) + ); + + $result = array_intersect(array_keys($this->customStrategies), $classHierarchy); + if ($result) { + return $this->customStrategies[array_shift($result)]; + } + + if ($object instanceof \Magento\Framework\DataObject\IdentityInterface) { + return $this->identifierStrategy; + } + + return $this->dummyStrategy; + } +} diff --git a/lib/internal/Magento/Framework/App/Cache/Tag/Strategy/Identifier.php b/lib/internal/Magento/Framework/App/Cache/Tag/Strategy/Identifier.php new file mode 100644 index 0000000000000..f4688e1e308f9 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Cache/Tag/Strategy/Identifier.php @@ -0,0 +1,30 @@ +getIdentities(); + } + + return []; + } +} diff --git a/lib/internal/Magento/Framework/App/Cache/Tag/StrategyInterface.php b/lib/internal/Magento/Framework/App/Cache/Tag/StrategyInterface.php new file mode 100644 index 0000000000000..f8c9c7ea12702 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Cache/Tag/StrategyInterface.php @@ -0,0 +1,21 @@ +_config = $config; $this->_factory = $factory; $this->_cacheState = $cacheState; $this->_cache = $cache; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -72,7 +83,7 @@ protected function _getInvalidatedTypes() { $types = $this->_cache->load(self::INVALIDATED_TYPES); if ($types) { - $types = unserialize($types); + $types = $this->serializer->unserialize($types); } else { $types = []; } @@ -87,7 +98,7 @@ protected function _getInvalidatedTypes() */ protected function _saveInvalidatedTypes($types) { - $this->_cache->save(serialize($types), self::INVALIDATED_TYPES); + $this->_cache->save($this->serializer->serialize($types), self::INVALIDATED_TYPES); } /** diff --git a/lib/internal/Magento/Framework/App/Cache/TypeListInterface.php b/lib/internal/Magento/Framework/App/Cache/TypeListInterface.php index 7ecbe664bfa03..baedfc0eb9725 100644 --- a/lib/internal/Magento/Framework/App/Cache/TypeListInterface.php +++ b/lib/internal/Magento/Framework/App/Cache/TypeListInterface.php @@ -1,6 +1,6 @@ _scopePool = $scopePool; + private $types; + + /** + * Config constructor. + * + * @param ScopeCodeResolver $scopeCodeResolver + * @param array $types + */ + public function __construct( + ScopeCodeResolver $scopeCodeResolver, + array $types = [] + ) { + $this->scopeCodeResolver = $scopeCodeResolver; + $this->types = $types; } /** @@ -42,7 +58,26 @@ public function getValue( $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null ) { - return $this->_scopePool->getScope($scope, $scopeCode)->getValue($path); + if ($scope === 'store') { + $scope = 'stores'; + } elseif ($scope === 'website') { + $scope = 'websites'; + } + $configPath = $scope; + if ($scope !== 'default') { + if (is_numeric($scopeCode) || $scopeCode === null) { + $scopeCode = $this->scopeCodeResolver->resolve($scope, $scopeCode); + } else if ($scopeCode instanceof \Magento\Framework\App\ScopeInterface) { + $scopeCode = $scopeCode->getCode(); + } + if ($scopeCode) { + $configPath .= '/' . $scopeCode; + } + } + if ($path) { + $configPath .= '/' . $path; + } + return $this->get('system', $configPath); } /** @@ -55,6 +90,45 @@ public function getValue( */ public function isSetFlag($path, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) { - return (bool) $this->getValue($path, $scope, $scopeCode); + return !!$this->getValue($path, $scope, $scopeCode); + } + + /** + * Invalidate cache by type + * + * @return void + */ + public function clean() + { + foreach ($this->types as $type) { + $type->clean(); + } + } + + /** + * Retrieve configuration. + * + * ('modules') - modules status configuration data + * ('scopes', 'websites/base') - base website data + * ('scopes', 'stores/default') - default store data + * + * ('system', 'default/web/seo/use_rewrites') - default system configuration data + * ('system', 'websites/base/web/seo/use_rewrites') - 'base' website system configuration data + * + * ('i18n', 'default/en_US') - translations for default store and 'en_US' locale + * + * @param string $configType + * @param string|null $path + * @param mixed|null $default + * @return array + */ + public function get($configType, $path = '', $default = null) + { + $result = null; + if (isset($this->types[$configType])) { + $result = $this->types[$configType]->get($path); + } + + return $result !== null ? $result : $default; } } diff --git a/lib/internal/Magento/Framework/App/Config/Base.php b/lib/internal/Magento/Framework/App/Config/Base.php index 3e2e1fdee7207..ac1a8ab503e84 100644 --- a/lib/internal/Magento/Framework/App/Config/Base.php +++ b/lib/internal/Magento/Framework/App/Config/Base.php @@ -3,7 +3,7 @@ * Abstract configuration class * Used to retrieve core configuration values * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Config; diff --git a/lib/internal/Magento/Framework/App/Config/BaseFactory.php b/lib/internal/Magento/Framework/App/Config/BaseFactory.php index 22d7af74f2bb1..29e82cfe210ce 100644 --- a/lib/internal/Magento/Framework/App/Config/BaseFactory.php +++ b/lib/internal/Magento/Framework/App/Config/BaseFactory.php @@ -2,7 +2,7 @@ /** * Base config model factory * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Config; diff --git a/lib/internal/Magento/Framework/App/Config/CommentInterface.php b/lib/internal/Magento/Framework/App/Config/CommentInterface.php new file mode 100644 index 0000000000000..86d1683b39fac --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/CommentInterface.php @@ -0,0 +1,21 @@ +scopeCodeResolver = $scopeCodeResolver; + } + + /** + * Creates full config path for given params. + * If $type variable was provided, it will be used as first part of path. + * + * @param string $path The path of configuration + * @param string $scope The scope of configuration + * @param string|int|null $scopeCode The scope code or its identifier. The values for this + * field are taken from 'store' or 'store_website' tables, depends on $scope value + * @param string|null $type The type of configuration. + * The available types are declared in implementations of Magento\Framework\App\Config\ConfigTypeInterface + * E.g. + * ```php + * const CONFIG_TYPE = 'system'; + * ``` + * @return string Resolved configuration path + */ + public function resolve($path, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null, $type = null) + { + $path = trim($path, '/'); + $scope = rtrim($scope, 's'); + + /** Scope name is currently stored in plural form. */ + if (in_array($scope, [ScopeInterface::SCOPE_STORE, ScopeInterface::SCOPE_WEBSITE])) { + $scope .= 's'; + } + + $scopePath = $type ? $type . '/' . $scope : $scope; + + if ($scope !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + if (is_numeric($scopeCode) || $scopeCode === null) { + $scopeCode = $this->scopeCodeResolver->resolve($scope, $scopeCode); + } + + $scopePath .= '/' . $scopeCode; + } + + return $scopePath . ($path ? '/' . $path : ''); + } +} diff --git a/lib/internal/Magento/Framework/App/Config/ConfigResource/ConfigInterface.php b/lib/internal/Magento/Framework/App/Config/ConfigResource/ConfigInterface.php index 293e27e367a19..37417d8af2320 100644 --- a/lib/internal/Magento/Framework/App/Config/ConfigResource/ConfigInterface.php +++ b/lib/internal/Magento/Framework/App/Config/ConfigResource/ConfigInterface.php @@ -1,6 +1,6 @@ sources = $sources; + } + + /** + * Retrieve aggregated configuration from all available sources. + * + * @param string $path + * @return string|array + */ + public function get($path = '') + { + $this->sortSources(); + $data = []; + foreach ($this->sources as $sourceConfig) { + /** @var ConfigSourceInterface $source */ + $source = $sourceConfig['source']; + $configData = $source->get($path); + if (!is_array($configData)) { + $data = $configData; + } elseif (!empty($configData)) { + $data = array_replace_recursive(is_array($data) ? $data : [], $configData); + } + } + return $data; + } + + /** + * Sort sources + * + * @return void + */ + private function sortSources() + { + uasort($this->sources, function ($firstItem, $secondItem) { + return $firstItem['sortOrder'] > $secondItem['sortOrder']; + }); + } +} diff --git a/lib/internal/Magento/Framework/App/Config/ConfigSourceInterface.php b/lib/internal/Magento/Framework/App/Config/ConfigSourceInterface.php new file mode 100644 index 0000000000000..5a1285210c8df --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/ConfigSourceInterface.php @@ -0,0 +1,37 @@ + + * [ + * 'field1' => 'value1', + * 'field2' => 'value2' + * ], + * 'group2' => + * [ + * 'field1' => 'value3' + * ] + * ] + * ``` + * And string will be returned if you use full path to field (e.g. scope/scope_code/section_id/group_id/field_id) + * E.g. 'value1' + */ + public function get($path = ''); +} diff --git a/lib/internal/Magento/Framework/App/Config/ConfigTypeInterface.php b/lib/internal/Magento/Framework/App/Config/ConfigTypeInterface.php new file mode 100644 index 0000000000000..f2373aac947cd --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/ConfigTypeInterface.php @@ -0,0 +1,27 @@ +serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(SerializerInterface::class); $data = $cache->load(self::CACHE_ID); if (!$data) { $data = $reader->read(); - $cache->save(serialize($data), self::CACHE_ID); + $cache->save($this->serializer->serialize($data), self::CACHE_ID); } else { - $data = unserialize($data); + $data = $this->serializer->unserialize($data); } $this->_data = $data['data']; $this->_metadata = $data['metadata']; diff --git a/lib/internal/Magento/Framework/App/Config/Initial/Converter.php b/lib/internal/Magento/Framework/App/Config/Initial/Converter.php index 9d6a719aa4d0f..5b139f9c5f066 100644 --- a/lib/internal/Magento/Framework/App/Config/Initial/Converter.php +++ b/lib/internal/Magento/Framework/App/Config/Initial/Converter.php @@ -2,7 +2,7 @@ /** * Initial configuration data converter. Converts \DOMDocument to array * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Config\Initial; diff --git a/lib/internal/Magento/Framework/App/Config/Initial/Reader.php b/lib/internal/Magento/Framework/App/Config/Initial/Reader.php index 3234fdc6eb333..5d79e17f822ec 100644 --- a/lib/internal/Magento/Framework/App/Config/Initial/Reader.php +++ b/lib/internal/Magento/Framework/App/Config/Initial/Reader.php @@ -2,7 +2,7 @@ /** * Default configuration data reader. Reads configuration data from storage * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Config\Initial; diff --git a/lib/internal/Magento/Framework/App/Config/Initial/SchemaLocator.php b/lib/internal/Magento/Framework/App/Config/Initial/SchemaLocator.php index cf3fd61f75df2..342532543f643 100644 --- a/lib/internal/Magento/Framework/App/Config/Initial/SchemaLocator.php +++ b/lib/internal/Magento/Framework/App/Config/Initial/SchemaLocator.php @@ -2,7 +2,7 @@ /** * Logging schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Config\Initial; diff --git a/lib/internal/Magento/Framework/App/Config/InitialConfigSource.php b/lib/internal/Magento/Framework/App/Config/InitialConfigSource.php new file mode 100644 index 0000000000000..1c1b3e9272a13 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/InitialConfigSource.php @@ -0,0 +1,56 @@ +reader = $reader; + $this->configType = $configType; + $this->fileKey = $fileKey; + } + + /** + * @inheritdoc + */ + public function get($path = '') + { + $data = new DataObject($this->reader->load($this->fileKey)); + if ($path !== '' && $path !== null) { + $path = '/' . $path; + } + return $data->getData($this->configType . $path) ?: []; + } +} diff --git a/lib/internal/Magento/Framework/App/Config/MetadataConfigTypeProcessor.php b/lib/internal/Magento/Framework/App/Config/MetadataConfigTypeProcessor.php new file mode 100644 index 0000000000000..7123a35da4088 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/MetadataConfigTypeProcessor.php @@ -0,0 +1,116 @@ +_processorFactory = $processorFactory; + $this->_metadata = $initialConfig->getMetadata(); + } + + /** + * Retrieve array value by path + * + * @param array $data + * @param string $path + * @return string|null + */ + protected function _getValue(array $data, $path) + { + $keys = explode('/', $path); + foreach ($keys as $key) { + if (is_array($data) && array_key_exists($key, $data)) { + $data = $data[$key]; + } else { + return null; + } + } + return $data; + } + + /** + * Set array value by path + * + * @param array &$container + * @param string $path + * @param string $value + * @return void + */ + protected function _setValue(array &$container, $path, $value) + { + $segments = explode('/', $path); + $currentPointer = & $container; + foreach ($segments as $segment) { + if (!isset($currentPointer[$segment])) { + $currentPointer[$segment] = []; + } + $currentPointer = & $currentPointer[$segment]; + } + $currentPointer = $value; + } + + /** + * Process data by sections: stores, default, websites and by scope codes + * + * @param array $data + * @return array + */ + private function processScopeData(array $data) + { + foreach ($this->_metadata as $path => $metadata) { + /** @var \Magento\Framework\App\Config\Data\ProcessorInterface $processor */ + $processor = $this->_processorFactory->get($metadata['backendModel']); + $value = $processor->processValue($this->_getValue($data, $path)); + $this->_setValue($data, $path, $value); + } + + return $data; + } + + /** + * Process config data + * + * @param array $data + * @return array + */ + public function process(array $rawData) + { + $processedData = []; + foreach ($rawData as $scope => $scopeData) { + if ($scope == ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { + $processedData[ScopeConfigInterface::SCOPE_TYPE_DEFAULT] = $this->processScopeData($scopeData); + } else { + foreach ($scopeData as $scopeCode => $data) { + $processedData[$scope][$scopeCode] = $this->processScopeData($data); + } + } + } + + return $processedData; + } +} diff --git a/lib/internal/Magento/Framework/App/Config/MetadataProcessor.php b/lib/internal/Magento/Framework/App/Config/MetadataProcessor.php index 0c3ebf1eaaf10..bbb33a170bd18 100644 --- a/lib/internal/Magento/Framework/App/Config/MetadataProcessor.php +++ b/lib/internal/Magento/Framework/App/Config/MetadataProcessor.php @@ -2,7 +2,7 @@ /** * Configuration metadata processor * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Config; diff --git a/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php b/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php index 7341804276594..5f4ddb9ac9a5e 100644 --- a/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php +++ b/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php @@ -2,7 +2,7 @@ /** * Configuration interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/App/Config/PostProcessorComposite.php b/lib/internal/Magento/Framework/App/Config/PostProcessorComposite.php new file mode 100644 index 0000000000000..30a7e62b5658f --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/PostProcessorComposite.php @@ -0,0 +1,39 @@ +processors = $processors; + } + + /** + * @param array $config + * @return array + */ + public function process(array $config) + { + foreach ($this->processors as $processor) { + $config = $processor->process($config); + } + + return $config; + } +} diff --git a/lib/internal/Magento/Framework/App/Config/PreProcessorComposite.php b/lib/internal/Magento/Framework/App/Config/PreProcessorComposite.php new file mode 100644 index 0000000000000..69097b16d899f --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/PreProcessorComposite.php @@ -0,0 +1,40 @@ +processors = $processors; + } + + /** + * @inheritdoc + */ + public function process(array $config) + { + /** @var PreProcessorInterface $processor */ + foreach ($this->processors as $processor) { + $config = $processor->process($config); + } + + return $config; + } +} diff --git a/lib/internal/Magento/Framework/App/Config/Reader/Source/SourceInterface.php b/lib/internal/Magento/Framework/App/Config/Reader/Source/SourceInterface.php new file mode 100644 index 0000000000000..48084e46c1f10 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/Reader/Source/SourceInterface.php @@ -0,0 +1,22 @@ +scopeResolverPool = $scopeResolverPool; + } + + /** + * Resolve scope code + * + * @param string $scopeType + * @param string $scopeCode + * @return string + */ + public function resolve($scopeType, $scopeCode) + { + if (isset($this->resolvedScopeCodes[$scopeType][$scopeCode])) { + return $this->resolvedScopeCodes[$scopeType][$scopeCode]; + } + if (($scopeCode === null || is_numeric($scopeCode)) + && $scopeType !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ) { + $scopeResolver = $this->scopeResolverPool->get($scopeType); + $resolverScopeCode = $scopeResolver->getScope($scopeCode); + } else { + $resolverScopeCode = $scopeCode; + } + + if ($resolverScopeCode instanceof \Magento\Framework\App\ScopeInterface) { + $resolverScopeCode = $resolverScopeCode->getCode(); + } + + $this->resolvedScopeCodes[$scopeType][$scopeCode] = $resolverScopeCode; + return $resolverScopeCode; + } +} diff --git a/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php b/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php index f3129d215ff14..bd663bc326d62 100644 --- a/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php +++ b/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php @@ -2,7 +2,7 @@ /** * Configuration interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/App/Config/ScopePool.php b/lib/internal/Magento/Framework/App/Config/ScopePool.php deleted file mode 100644 index d366349722f0f..0000000000000 --- a/lib/internal/Magento/Framework/App/Config/ScopePool.php +++ /dev/null @@ -1,154 +0,0 @@ -_readerPool = $readerPool; - $this->_dataFactory = $dataFactory; - $this->_cache = $cache; - $this->_cacheId = $cacheId; - $this->_scopeResolverPool = $scopeResolverPool; - } - - /** - * @return RequestInterface - */ - private function getRequest() - { - if ($this->request === null) { - $this->request = \Magento\Framework\App\ObjectManager::getInstance()->get(RequestInterface::class); - } - return $this->request; - } - - /** - * Retrieve config section - * - * @param string $scopeType - * @param string|\Magento\Framework\DataObject|null $scopeCode - * @return \Magento\Framework\App\Config\DataInterface - */ - public function getScope($scopeType, $scopeCode = null) - { - $scopeCode = $this->_getScopeCode($scopeType, $scopeCode); - - // Key by url to support dynamic {{base_url}} and port assignments - $host = $this->getRequest()->getHttpHost(); - $port = $this->getRequest()->getServer('SERVER_PORT'); - $path = $this->getRequest()->getBasePath(); - $urlInfo = $host . $port . trim($path, '/'); - $code = $scopeType . '|' . $scopeCode . '|' . $urlInfo; - - if (!isset($this->_scopes[$code])) { - $cacheKey = $this->_cacheId . '|' . $code; - $data = $this->_cache->load($cacheKey); - if ($data) { - $data = unserialize($data); - } else { - $reader = $this->_readerPool->getReader($scopeType); - if ($scopeType === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) { - $data = $reader->read(); - } else { - $data = $reader->read($scopeCode); - } - $this->_cache->save(serialize($data), $cacheKey, [self::CACHE_TAG]); - } - $this->_scopes[$code] = $this->_dataFactory->create(['data' => $data]); - } - return $this->_scopes[$code]; - } - - /** - * Clear cache of all scopes - * - * @return void - */ - public function clean() - { - $this->_scopes = []; - $this->_cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [self::CACHE_TAG]); - } - - /** - * Retrieve scope code value - * - * @param string $scopeType - * @param string|\Magento\Framework\DataObject|null $scopeCode - * @return string - */ - protected function _getScopeCode($scopeType, $scopeCode) - { - if (($scopeCode === null || is_numeric($scopeCode)) - && $scopeType !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT - ) { - $scopeResolver = $this->_scopeResolverPool->get($scopeType); - $scopeCode = $scopeResolver->getScope($scopeCode); - } - - if ($scopeCode instanceof \Magento\Framework\App\ScopeInterface) { - $scopeCode = $scopeCode->getCode(); - } - - return $scopeCode; - } -} diff --git a/lib/internal/Magento/Framework/App/Config/Spi/PostProcessorInterface.php b/lib/internal/Magento/Framework/App/Config/Spi/PostProcessorInterface.php new file mode 100644 index 0000000000000..1e0dc614dce36 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Config/Spi/PostProcessorInterface.php @@ -0,0 +1,27 @@ +data = null; } + /** + * Check if data from deploy files is avaiable + * + * @return bool + */ + public function isDbAvailable() + { + $this->load(); + return isset($this->data['db']); + } + /** * Loads the configuration data * diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php index 6a4af75512d4d..8cb773e47eea9 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php @@ -1,6 +1,6 @@ files; + $path = $this->dirList->getPath(DirectoryList::CONFIG); + $fileDriver = $this->driverPool->getDriver(DriverPool::FILE); + $initialFilePools = $this->configFilePool->getInitialFilePools(); + + $files = []; + foreach ($this->files as $fileKey => $filePath) { + $files[$fileKey] = $filePath; + if (!$fileDriver->isExists($path . "/" . $filePath)) { + foreach ($initialFilePools as $initialFiles) { + if ( + isset($initialFiles[$fileKey]) + && $fileDriver->isExists($path . '/' . $initialFiles[$fileKey]) + ) { + $files[$fileKey] = $initialFiles[$fileKey]; + } + } + } + } + + return $files; } /** @@ -84,26 +103,19 @@ public function getFiles() */ public function load($fileKey = null) { - $path = $this->dirList->getPath(DirectoryList::CONFIG); - $fileDriver = $this->driverPool->getDriver(DriverPool::FILE); - $result = []; if ($fileKey) { - $filePath = $path . '/' . $this->configFilePool->getPath($fileKey); - if ($fileDriver->isExists($filePath)) { - $result = include $filePath; - } + $pathConfig = $this->configFilePool->getPath($fileKey); + return $this->loadConfigFile($fileKey, $pathConfig); } else { $configFiles = $this->configFilePool->getPaths(); $allFilesData = []; $result = []; - foreach (array_keys($configFiles) as $fileKey) { - $configFile = $path . '/' . $this->configFilePool->getPath($fileKey); - if ($fileDriver->isExists($configFile)) { - $fileData = include $configFile; - } else { + foreach ($configFiles as $fileKey => $pathConfig) { + $fileData = $this->loadConfigFile($fileKey, $pathConfig); + if (!$fileData) { continue; } - $allFilesData[$configFile] = $fileData; + $allFilesData[$fileKey] = $fileData; if (!empty($fileData)) { $intersection = array_intersect_key($result, $fileData); if (!empty($intersection)) { @@ -116,8 +128,47 @@ public function load($fileKey = null) $result = array_merge($result, $fileData); } } + return $result; } - return $result ?: []; + } + + /** + * @param string $fileKey + * @param string $pathConfig + * @param bool $ignoreInitialConfigFiles + * @return array + */ + public function loadConfigFile($fileKey, $pathConfig, $ignoreInitialConfigFiles = false) + { + $result = []; + $initialFilePools = $this->configFilePool->getInitialFilePools(); + $path = $this->dirList->getPath(DirectoryList::CONFIG); + $fileDriver = $this->driverPool->getDriver(DriverPool::FILE); + + if (!$ignoreInitialConfigFiles) { + foreach ($initialFilePools as $initialFiles) { + if (isset($initialFiles[$fileKey]) && $fileDriver->isExists($path . '/' . $initialFiles[$fileKey])) { + $fileBuffer = include $path . '/' . $initialFiles[$fileKey]; + if (is_array($fileBuffer)) { + $result = array_replace_recursive($result, $fileBuffer); + } + } + } + } + + if ($fileDriver->isExists($path . '/' . $pathConfig)) { + $fileBuffer = include $path . '/' . $pathConfig; + $result = array_replace_recursive($result, $fileBuffer); + } + + if ($fileDriver->isExists($path . '/' . $pathConfig)) { + $configResult = include $path . '/' . $pathConfig; + if (is_array($configResult)) { + $result = array_replace_recursive($result, $configResult); + } + } + + return $result; } /** diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php index ac1e5f6ecf897..badbea2b8b934 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer.php @@ -1,6 +1,6 @@ configFilePool->getPaths(); - foreach ($data as $fileKey => $config) { - if (isset($paths[$fileKey])) { + $paths = $pool ? $this->configFilePool->getPathsByPool($pool) : $this->configFilePool->getPaths(); - if ($this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->isExist($paths[$fileKey])) { - $currentData = $this->reader->load($fileKey); + if (isset($paths[$fileKey])) { + $currentData = $this->reader->loadConfigFile($fileKey, $paths[$fileKey], true); + if ($currentData) { if ($override) { $config = array_merge($currentData, $config); } else { @@ -111,9 +113,10 @@ public function saveConfig(array $data, $override = false) } } - $contents = $this->formatter->format($config); + $contents = $this->formatter->format($config, $comments); try { - $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile($paths[$fileKey], $contents); + $writeFilePath = $paths[$fileKey]; + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile($writeFilePath, $contents); } catch (FileSystemException $e) { throw new FileSystemException( new Phrase('Deployment config file %1 is not writable.', [$paths[$fileKey]]) diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php index 24e31074501f3..a1693547123ef 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/FormatterInterface.php @@ -1,6 +1,6 @@ $value) { + $comment = ' '; + if (!empty($comments[$key])) { + $exportedComment = is_string($comments[$key]) + ? $comments[$key] + : var_export($comments[$key], true); + $comment = " /**\n * " . str_replace("\n", "\n * ", $exportedComment) . "\n */\n"; + } + $space = is_array($value) ? " \n" : ' '; + $elements[] = $comment . var_export($key, true) . ' =>' . $space . var_export($value, true); + } + return " [parent::PATH => 'var'], self::CACHE => [parent::PATH => 'var/cache'], self::LOG => [parent::PATH => 'var/log'], - self::DI => [parent::PATH => 'var/di'], - self::GENERATION => [parent::PATH => 'var/generation'], + self::DI => [parent::PATH => 'generated/metadata'], + self::GENERATION => [parent::PATH => Io::DEFAULT_DIRECTORY], self::SESSION => [parent::PATH => 'var/session'], self::MEDIA => [parent::PATH => 'pub/media', parent::URL_PATH => 'pub/media'], self::STATIC_VIEW => [parent::PATH => 'pub/static', parent::URL_PATH => 'pub/static'], @@ -133,6 +157,9 @@ public static function getDefaultConfig() self::TEMPLATE_MINIFICATION_DIR => [parent::PATH => 'var/view_preprocessed/html'], self::SETUP => [parent::PATH => 'setup/src'], self::COMPOSER_HOME => [parent::PATH => 'var/composer_home'], + self::GENERATED => [parent::PATH => 'generated'], + self::GENERATED_CODE => [parent::PATH => Io::DEFAULT_DIRECTORY], + self::GENERATED_METADATA => [parent::PATH => 'generated/metadata'], ]; return parent::getDefaultConfig() + $result; } diff --git a/lib/internal/Magento/Framework/App/FrontController.php b/lib/internal/Magento/Framework/App/FrontController.php index 81a3e3f84379b..218d82f296106 100644 --- a/lib/internal/Magento/Framework/App/FrontController.php +++ b/lib/internal/Magento/Framework/App/FrontController.php @@ -2,7 +2,7 @@ /** * Front controller responsible for dispatching application requests * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App; diff --git a/lib/internal/Magento/Framework/App/FrontControllerInterface.php b/lib/internal/Magento/Framework/App/FrontControllerInterface.php index 2e8d15f62d9a1..20fc1da122105 100644 --- a/lib/internal/Magento/Framework/App/FrontControllerInterface.php +++ b/lib/internal/Magento/Framework/App/FrontControllerInterface.php @@ -2,7 +2,7 @@ /** * Application front controller responsible for dispatching application requests * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App; diff --git a/lib/internal/Magento/Framework/App/Helper/AbstractHelper.php b/lib/internal/Magento/Framework/App/Helper/AbstractHelper.php index e33badff9a638..2ad0aa0fcbe76 100644 --- a/lib/internal/Magento/Framework/App/Helper/AbstractHelper.php +++ b/lib/internal/Magento/Framework/App/Helper/AbstractHelper.php @@ -1,6 +1,6 @@ getDir($projectRoot) . "\n"; - $newMessage .= 'If you are using the sample nginx configuration, please go to ' - . $this->_request->getScheme(). '://' . $this->_request->getHttpHost() . $setupInfo->getUrl(); + throw new \Exception($newMessage, 0, $exception); } } diff --git a/lib/internal/Magento/Framework/App/Http/Context.php b/lib/internal/Magento/Framework/App/Http/Context.php index 4146dac725f03..9a9caff8864ea 100644 --- a/lib/internal/Magento/Framework/App/Http/Context.php +++ b/lib/internal/Magento/Framework/App/Http/Context.php @@ -1,6 +1,6 @@ data = $data; + $this->default = $default; + } + /** * Data setter * @@ -99,4 +109,17 @@ public function getVaryString() } return null; } + + /** + * Get data and default data in "key-value" format + * + * @return array + */ + public function toArray() + { + return [ + 'data' => $this->data, + 'default' => $this->default + ]; + } } diff --git a/lib/internal/Magento/Framework/App/Interception/Cache/CompiledConfig.php b/lib/internal/Magento/Framework/App/Interception/Cache/CompiledConfig.php index 0b173a07f1817..bf12cd3fe7712 100644 --- a/lib/internal/Magento/Framework/App/Interception/Cache/CompiledConfig.php +++ b/lib/internal/Magento/Framework/App/Interception/Cache/CompiledConfig.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/MaintenanceMode.php b/lib/internal/Magento/Framework/App/MaintenanceMode.php index 66ed4538231e9..fd5971779b7e1 100644 --- a/lib/internal/Magento/Framework/App/MaintenanceMode.php +++ b/lib/internal/Magento/Framework/App/MaintenanceMode.php @@ -1,6 +1,6 @@ data[$scope][$scopeCode][$path])) { + return $this->data[$scope][$scopeCode][$path]; + } + + return parent::getValue($path, $scope, $scopeCode); + } + /** * Set config value in the corresponding config scope * @@ -28,9 +51,15 @@ public function setValue( $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null ) { - if (empty($scopeCode)) { - $scopeCode = null; - } - $this->_scopePool->getScope($scope, $scopeCode)->setValue($path, $value); + $this->data[$scope][$scopeCode][$path] = $value; + } + + /** + * @inheritdoc + */ + public function clean() + { + $this->data = null; + parent::clean(); } } diff --git a/lib/internal/Magento/Framework/App/ObjectManager.php b/lib/internal/Magento/Framework/App/ObjectManager.php index 431a188038586..ee4f2b26d467f 100644 --- a/lib/internal/Magento/Framework/App/ObjectManager.php +++ b/lib/internal/Magento/Framework/App/ObjectManager.php @@ -1,6 +1,6 @@ _cacheFrontend->load($this->_prefix . $key)); + return $this->getSerializer()->unserialize($this->_cacheFrontend->load($this->_prefix . $key)); } /** @@ -49,6 +57,20 @@ public function get($key) */ public function save(array $config, $key) { - $this->_cacheFrontend->save(serialize($config), $this->_prefix . $key); + $this->_cacheFrontend->save($this->getSerializer()->serialize($config), $this->_prefix . $key); + } + + /** + * Get serializer + * + * @return SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if (null === $this->serializer) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()->get(Serialize::class); + } + return $this->serializer; } } diff --git a/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader.php b/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader.php index 2190ff6cdb37f..5aedf6003d7fa 100644 --- a/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader.php +++ b/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader.php @@ -2,11 +2,13 @@ /** * ObjectManager configuration loader * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\ObjectManager; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\Serialize\Serializer\Serialize; use Magento\Framework\ObjectManager\ConfigLoaderInterface; class ConfigLoader implements ConfigLoaderInterface @@ -32,6 +34,11 @@ class ConfigLoader implements ConfigLoaderInterface */ protected $_cache; + /** + * @var SerializerInterface + */ + private $serializer; + /** * @param \Magento\Framework\Config\CacheInterface $cache * @param \Magento\Framework\ObjectManager\Config\Reader\DomFactory $readerFactory @@ -67,11 +74,25 @@ public function load($area) if (!$data) { $data = $this->_getReader()->read($area); - $this->_cache->save(serialize($data), $cacheId); + $this->_cache->save($this->getSerializer()->serialize($data), $cacheId); } else { - $data = unserialize($data); + $data = $this->getSerializer()->unserialize($data); } return $data; } + + /** + * Get serializer + * + * @return SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if (null === $this->serializer) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()->get(Serialize::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader/Compiled.php b/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader/Compiled.php index 844d3f038aefe..328c9b0da7bce 100644 --- a/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader/Compiled.php +++ b/lib/internal/Magento/Framework/App/ObjectManager/ConfigLoader/Compiled.php @@ -1,12 +1,15 @@ configCache[$area])) { return $this->configCache[$area]; } - $this->configCache[$area] = \unserialize(\file_get_contents(self::getFilePath($area))); + $this->configCache[$area] = $this->getSerializer()->unserialize(\file_get_contents(self::getFilePath($area))); return $this->configCache[$area]; } /** - * Returns path to cached configuration + * Returns path to compiled configuration * * @param string $area * @return string */ public static function getFilePath($area) { - return BP . '/var/di/' . $area . '.ser'; + $diPath = DirectoryList::getDefaultConfig()[DirectoryList::GENERATED_METADATA][DirectoryList::PATH]; + return BP . '/' . $diPath . '/' . $area . '.ser'; + } + + /** + * Get serializer + * + * @return SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if (null === $this->serializer) { + $this->serializer = new Serialize(); + } + return $this->serializer; } } diff --git a/lib/internal/Magento/Framework/App/ObjectManager/Environment/AbstractEnvironment.php b/lib/internal/Magento/Framework/App/ObjectManager/Environment/AbstractEnvironment.php index e43cce2723054..c1200acc444ab 100644 --- a/lib/internal/Magento/Framework/App/ObjectManager/Environment/AbstractEnvironment.php +++ b/lib/internal/Magento/Framework/App/ObjectManager/Environment/AbstractEnvironment.php @@ -1,6 +1,6 @@ get(), $arguments); $definitionFactory = new \Magento\Framework\ObjectManager\DefinitionFactory( $this->driverPool->getDriver(DriverPool::FILE), - $this->directoryList->getPath(DirectoryList::DI), - $this->directoryList->getPath(DirectoryList::GENERATION), - $deploymentConfig->get(self::CONFIG_PATH_DEFINITION_FORMAT, Serialized::MODE_NAME) + $this->directoryList->getPath(DirectoryList::GENERATED_CODE) ); - $definitions = $definitionFactory->createClassDefinition($deploymentConfig->get('definitions')); + $definitions = $definitionFactory->createClassDefinition(); $relations = $definitionFactory->createRelations(); /** @var EnvironmentFactory $envFactory */ $envFactory = new $this->envFactoryClassName($relations, $definitions); /** @var EnvironmentInterface $env */ - $env = $envFactory->createEnvironment(); + $env = $envFactory->createEnvironment(); /** @var ConfigInterface $diConfig */ $diConfig = $env->getDiConfig(); @@ -298,6 +287,8 @@ protected function _loadPrimaryConfig(DirectoryList $directoryList, $driverPool, * @param \Magento\Framework\ObjectManager\Config\Config $diConfig * @param \Magento\Framework\ObjectManager\DefinitionInterface $definitions * @return \Magento\Framework\Interception\PluginList\PluginList + * @deprecated + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ protected function _createPluginList( \Magento\Framework\ObjectManagerInterface $objectManager, @@ -312,8 +303,7 @@ protected function _createPluginList( 'relations' => $relations, 'definitions' => $definitionFactory->createPluginDefinition(), 'omConfig' => $diConfig, - 'classDefinitions' => $definitions instanceof - \Magento\Framework\ObjectManager\Definition\Compiled ? $definitions : null + 'classDefinitions' => null ] ); } diff --git a/lib/internal/Magento/Framework/App/PageCache/Cache.php b/lib/internal/Magento/Framework/App/PageCache/Cache.php index d219f5acf345a..92973f6b06095 100644 --- a/lib/internal/Magento/Framework/App/PageCache/Cache.php +++ b/lib/internal/Magento/Framework/App/PageCache/Cache.php @@ -1,6 +1,6 @@ cache = $cache; $this->identifier = $identifier; $this->request = $request; + + if ($context) { + $this->context = $context; + } else { + $this->context = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\App\Http\Context::class + ); + } + if ($contextFactory) { + $this->contextFactory = $contextFactory; + } else { + $this->contextFactory = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\App\Http\ContextFactory::class + ); + } + if ($httpFactory) { + $this->httpFactory = $httpFactory; + } else { + $this->httpFactory = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\App\Response\HttpFactory::class + ); + } + if ($serializer) { + $this->serializer = $serializer; + } else { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\Serialize\SerializerInterface::class + ); + } } /** @@ -57,7 +112,12 @@ public function __construct( public function load() { if ($this->request->isGet() || $this->request->isHead()) { - return unserialize($this->getCache()->load($this->identifier->getValue())); + $responseData = $this->serializer->unserialize($this->getCache()->load($this->identifier->getValue())); + if (!$responseData) { + return false; + } + + return $this->buildResponse($responseData); } return false; } @@ -84,11 +144,63 @@ public function process(\Magento\Framework\App\Response\Http $response) if (!headers_sent()) { header_remove('Set-Cookie'); } - $this->getCache()->save(serialize($response), $this->identifier->getValue(), $tags, $maxAge); + + $this->getCache()->save( + $this->serializer->serialize($this->getPreparedData($response)), + $this->identifier->getValue(), + $tags, + $maxAge + ); } } } + /** + * Get prepared data for storage in the cache. + * + * @param \Magento\Framework\App\Response\Http $response + * @return array + */ + private function getPreparedData(\Magento\Framework\App\Response\Http $response) + { + return [ + 'content' => $response->getContent(), + 'status_code' => $response->getStatusCode(), + 'headers' => $response->getHeaders()->toArray(), + 'context' => $this->context->toArray() + ]; + + } + + /** + * Build response using response data. + * + * @param array $responseData + * @return \Magento\Framework\App\Response\Http + */ + private function buildResponse($responseData) + { + $context = $this->contextFactory->create( + [ + 'data' => $responseData['context']['data'], + 'default' => $responseData['context']['default'] + ] + ); + + $response = $this->httpFactory->create( + [ + 'context' => $context + ] + ); + $response->setStatusCode($responseData['status_code']); + $response->setContent($responseData['content']); + foreach ($responseData['headers'] as $headerKey => $headerValue) { + $response->setHeader($headerKey, $headerValue, true); + } + + return $response; + } + /** * TODO: Workaround to support backwards compatibility, will rework to use Dependency Injection in MAGETWO-49547 * @@ -97,7 +209,9 @@ public function process(\Magento\Framework\App\Response\Http $response) private function getCache() { if (!$this->fullPageCache) { - $this->fullPageCache = ObjectManager::getInstance()->get(\Magento\PageCache\Model\Cache\Type::class); + $this->fullPageCache = \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\PageCache\Model\Cache\Type::class + ); } return $this->fullPageCache; } diff --git a/lib/internal/Magento/Framework/App/PageCache/NotCacheableInterface.php b/lib/internal/Magento/Framework/App/PageCache/NotCacheableInterface.php index 9b85906c3a937..59eb7f690f687 100644 --- a/lib/internal/Magento/Framework/App/PageCache/NotCacheableInterface.php +++ b/lib/internal/Magento/Framework/App/PageCache/NotCacheableInterface.php @@ -2,7 +2,7 @@ /** * HTTP response interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\PageCache; diff --git a/lib/internal/Magento/Framework/App/PageCache/Version.php b/lib/internal/Magento/Framework/App/PageCache/Version.php index 272ad8ce5c02f..3b7f9145801a7 100644 --- a/lib/internal/Magento/Framework/App/PageCache/Version.php +++ b/lib/internal/Magento/Framework/App/PageCache/Version.php @@ -1,6 +1,6 @@ _scopePool->clean(); + $this->clean(); return $this; } } diff --git a/lib/internal/Magento/Framework/App/Request/DataPersistor.php b/lib/internal/Magento/Framework/App/Request/DataPersistor.php index 64e77d68aa8fb..6735cc4b5d0d5 100644 --- a/lib/internal/Magento/Framework/App/Request/DataPersistor.php +++ b/lib/internal/Magento/Framework/App/Request/DataPersistor.php @@ -1,6 +1,6 @@ getConnectionByName($connectionName); } + /** + * @param string $resourceName + * @return void + */ + public function closeConnection($resourceName = self::DEFAULT_CONNECTION) + { + $processConnectionName = $this->getProcessConnectionName($this->config->getConnectionName($resourceName)); + if (isset($this->connections[$processConnectionName])) { + $this->connections[$processConnectionName] = null; + } + } + /** * Retrieve connection by $connectionName * @@ -101,8 +113,9 @@ public function getConnection($resourceName = self::DEFAULT_CONNECTION) */ public function getConnectionByName($connectionName) { - if (isset($this->connections[$connectionName])) { - return $this->connections[$connectionName]; + $processConnectionName = $this->getProcessConnectionName($connectionName); + if (isset($this->connections[$processConnectionName])) { + return $this->connections[$processConnectionName]; } $connectionConfig = $this->deploymentConfig->get( @@ -115,10 +128,19 @@ public function getConnectionByName($connectionName) throw new \DomainException('Connection "' . $connectionName . '" is not defined'); } - $this->connections[$connectionName] = $connection; + $this->connections[$processConnectionName] = $connection; return $connection; } + /** + * @param string $connectionName + * @return string + */ + private function getProcessConnectionName($connectionName) + { + return $connectionName . '_process_' . getmypid(); + } + /** * Get resource table name, validated by db adapter * diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/Config.php b/lib/internal/Magento/Framework/App/ResourceConnection/Config.php index 9cd03c8372e17..d518d080a368c 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/Config.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/Config.php @@ -1,14 +1,16 @@ getConfigData(ConfigOptionsListConstants::KEY_RESOURCE); - foreach ($resource as $resourceName => $resourceData) { - if (!isset($resourceData['connection'])) { - throw new \InvalidArgumentException('Invalid initial resource configuration'); - } - $this->_connectionNames[$resourceName] = $resourceData['connection']; - } + parent::__construct($reader, $configScope, $cache, $cacheId, $serializer); + $this->deploymentConfig = $deploymentConfig; } /** @@ -52,6 +61,7 @@ public function __construct( */ public function getConnectionName($resourceName) { + $this->initConnections(); $connectionName = \Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION; $resourceName = preg_replace("/_setup$/", '', $resourceName); @@ -80,4 +90,23 @@ public function getConnectionName($resourceName) return $connectionName; } + + /** + * Initialise connections + * + * @return void + */ + private function initConnections() + { + if (!$this->initialized) { + $this->initialized = true; + $resource = $this->deploymentConfig->getConfigData(ConfigOptionsListConstants::KEY_RESOURCE) ?: []; + foreach ($resource as $resourceName => $resourceData) { + if (!isset($resourceData['connection'])) { + throw new \InvalidArgumentException('Invalid initial resource configuration'); + } + $this->_connectionNames[$resourceName] = $resourceData['connection']; + } + } + } } diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/Config/Converter.php b/lib/internal/Magento/Framework/App/ResourceConnection/Config/Converter.php index 38617804de316..b3ab814a8a6a3 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/Config/Converter.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/Config/Converter.php @@ -2,7 +2,7 @@ /** * Converter of resources configuration from \DOMDocument to array * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\ResourceConnection\Config; diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/Config/Reader.php b/lib/internal/Magento/Framework/App/ResourceConnection/Config/Reader.php index ef82032b15203..de03874d9f8e4 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/Config/Reader.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/Config/Reader.php @@ -2,7 +2,7 @@ /** * Resources configuration filesystem loader * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\ResourceConnection\Config; diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/Config/SchemaLocator.php b/lib/internal/Magento/Framework/App/ResourceConnection/Config/SchemaLocator.php index 318ddb1f4f8b3..b5ec63b90c13a 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/Config/SchemaLocator.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/Config/SchemaLocator.php @@ -2,7 +2,7 @@ /** * Resource configuration schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\ResourceConnection\Config; diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/ConfigInterface.php b/lib/internal/Magento/Framework/App/ResourceConnection/ConfigInterface.php index 8e8765ca92194..44ba04a265a4c 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/ConfigInterface.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/ConfigInterface.php @@ -2,7 +2,7 @@ /** * Resource configuration interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\ResourceConnection; diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionAdapterInterface.php b/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionAdapterInterface.php index b340562e26945..dca63188c9ce8 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionAdapterInterface.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionAdapterInterface.php @@ -2,7 +2,7 @@ /** * Connection adapter interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\ResourceConnection; diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionFactory.php b/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionFactory.php index 3fa75c50bdc77..624bf470537d4 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionFactory.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/ConnectionFactory.php @@ -2,7 +2,7 @@ /** * Connection adapter factory * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\ResourceConnection; diff --git a/lib/internal/Magento/Framework/App/ResourceConnection/SourceFactory.php b/lib/internal/Magento/Framework/App/ResourceConnection/SourceFactory.php index ea6bbcf9a540e..c001458f17371 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection/SourceFactory.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection/SourceFactory.php @@ -1,6 +1,6 @@ _routes[$scope]; } $cacheId = $scope . '::' . $this->_cacheId; - $cachedRoutes = unserialize($this->_cache->load($cacheId)); + $cachedRoutes = $this->getSerializer()->unserialize($this->_cache->load($cacheId)); if (is_array($cachedRoutes)) { $this->_routes[$scope] = $cachedRoutes; return $cachedRoutes; @@ -81,7 +88,8 @@ protected function _getRoutes($scope = null) $routers = $this->_reader->read($scope); $routes = $routers[$this->_areaList->getDefaultRouter($scope)]['routes']; - $this->_cache->save(serialize($routes), $cacheId); + $routesData = $this->getSerializer()->serialize($routes); + $this->_cache->save($routesData, $cacheId); $this->_routes[$scope] = $routes; return $routes; } @@ -133,4 +141,19 @@ public function getModulesByFrontName($frontName, $scope = null) return array_unique($modules); } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/App/Route/Config/Converter.php b/lib/internal/Magento/Framework/App/Route/Config/Converter.php index fe0abe9b4a638..630635ca4cecd 100644 --- a/lib/internal/Magento/Framework/App/Route/Config/Converter.php +++ b/lib/internal/Magento/Framework/App/Route/Config/Converter.php @@ -2,7 +2,7 @@ /** * Routes configuration converter * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Route\Config; diff --git a/lib/internal/Magento/Framework/App/Route/Config/Reader.php b/lib/internal/Magento/Framework/App/Route/Config/Reader.php index ad316829508e0..91b6117b78446 100644 --- a/lib/internal/Magento/Framework/App/Route/Config/Reader.php +++ b/lib/internal/Magento/Framework/App/Route/Config/Reader.php @@ -2,7 +2,7 @@ /** * Routes configuration reader * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Route\Config; diff --git a/lib/internal/Magento/Framework/App/Route/Config/SchemaLocator.php b/lib/internal/Magento/Framework/App/Route/Config/SchemaLocator.php index 3b4f44b5b8529..eb2057b79d0af 100644 --- a/lib/internal/Magento/Framework/App/Route/Config/SchemaLocator.php +++ b/lib/internal/Magento/Framework/App/Route/Config/SchemaLocator.php @@ -2,7 +2,7 @@ /** * Routes configuration schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Route\Config; diff --git a/lib/internal/Magento/Framework/App/Route/ConfigInterface.php b/lib/internal/Magento/Framework/App/Route/ConfigInterface.php index be5953ff98940..d2c62b87eb747 100644 --- a/lib/internal/Magento/Framework/App/Route/ConfigInterface.php +++ b/lib/internal/Magento/Framework/App/Route/ConfigInterface.php @@ -1,6 +1,6 @@ reservedWords = array_merge($reservedWords, $this->reservedWords); $this->actionInterface = $actionInterface; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()->get(Serialize::class); $data = $cache->load($cacheKey); if (!$data) { $this->actions = $moduleReader->getActionFiles(); - $cache->save(serialize($this->actions), $cacheKey); + $cache->save($this->serializer->serialize($this->actions), $cacheKey); } else { - $this->actions = unserialize($data); + $this->actions = $this->serializer->unserialize($data); } } diff --git a/lib/internal/Magento/Framework/App/Router/Base.php b/lib/internal/Magento/Framework/App/Router/Base.php index 9be1788387323..87a6ec794eefc 100644 --- a/lib/internal/Magento/Framework/App/Router/Base.php +++ b/lib/internal/Magento/Framework/App/Router/Base.php @@ -2,14 +2,11 @@ /** * Base router * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Router; -use Magento\Framework\App\RequestInterface; -use Magento\Store\Model\ScopeInterface; - /** * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) diff --git a/lib/internal/Magento/Framework/App/Router/DefaultRouter.php b/lib/internal/Magento/Framework/App/Router/DefaultRouter.php index 4cfff32c1d34c..670fb2923be0a 100644 --- a/lib/internal/Magento/Framework/App/Router/DefaultRouter.php +++ b/lib/internal/Magento/Framework/App/Router/DefaultRouter.php @@ -2,7 +2,7 @@ /** * Default application router * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Router; diff --git a/lib/internal/Magento/Framework/App/Router/NoRouteHandler.php b/lib/internal/Magento/Framework/App/Router/NoRouteHandler.php index b8f6930176dd5..30fddce555c17 100644 --- a/lib/internal/Magento/Framework/App/Router/NoRouteHandler.php +++ b/lib/internal/Magento/Framework/App/Router/NoRouteHandler.php @@ -2,7 +2,7 @@ /** * Default no route handler * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Router; diff --git a/lib/internal/Magento/Framework/App/Router/NoRouteHandlerInterface.php b/lib/internal/Magento/Framework/App/Router/NoRouteHandlerInterface.php index cf0b44d42933c..612efcd788221 100644 --- a/lib/internal/Magento/Framework/App/Router/NoRouteHandlerInterface.php +++ b/lib/internal/Magento/Framework/App/Router/NoRouteHandlerInterface.php @@ -2,7 +2,7 @@ /** * No route handler interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Router; diff --git a/lib/internal/Magento/Framework/App/Router/NoRouteHandlerList.php b/lib/internal/Magento/Framework/App/Router/NoRouteHandlerList.php index cca974105af3a..40bca4d9e327d 100644 --- a/lib/internal/Magento/Framework/App/Router/NoRouteHandlerList.php +++ b/lib/internal/Magento/Framework/App/Router/NoRouteHandlerList.php @@ -2,7 +2,7 @@ /** * No route handlers retriever * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Router; diff --git a/lib/internal/Magento/Framework/App/Router/PathConfigInterface.php b/lib/internal/Magento/Framework/App/Router/PathConfigInterface.php index ba8a74ff6a35d..08b1687936140 100644 --- a/lib/internal/Magento/Framework/App/Router/PathConfigInterface.php +++ b/lib/internal/Magento/Framework/App/Router/PathConfigInterface.php @@ -1,6 +1,6 @@ scopeResolverPool = $scopeResolverPool; + } + + /** + * {@inheritdoc} + */ + public function isValid($scope, $scopeCode = null) + { + if ($scope === ScopeConfigInterface::SCOPE_TYPE_DEFAULT && empty($scopeCode)) { + return true; + } + + if ($scope === ScopeConfigInterface::SCOPE_TYPE_DEFAULT && !empty($scopeCode)) { + throw new LocalizedException(new Phrase( + 'The "%1" scope can\'t include a scope code. Try again without entering a scope code.', + [ScopeConfigInterface::SCOPE_TYPE_DEFAULT] + )); + } + + if (empty($scope)) { + throw new LocalizedException(new Phrase('Enter a scope before proceeding.')); + } + + $this->validateScopeCode($scopeCode); + + try { + $scopeResolver = $this->scopeResolverPool->get($scope); + $scopeResolver->getScope($scopeCode)->getId(); + } catch (InvalidArgumentException $e) { + throw new LocalizedException(new Phrase('The "%1" value doesn\'t exist. Enter another value.', [$scope])); + } catch (NoSuchEntityException $e) { + throw new LocalizedException( + new Phrase('The "%1" value doesn\'t exist. Enter another value.', [$scopeCode]) + ); + } + + return true; + } + + /** + * Validate scope code + * Throw exception if not valid. + * + * @param string $scopeCode + * @return void + * @throws LocalizedException if scope code is empty or has a wrong format + */ + private function validateScopeCode($scopeCode) + { + if (empty($scopeCode)) { + throw new LocalizedException(new Phrase('Enter a scope code before proceeding.')); + } + + if (!preg_match('/^[a-z]+[a-z0-9_]*$/', $scopeCode)) { + throw new LocalizedException(new Phrase( + 'The scope code can include only lowercase letters (a-z), numbers (0-9) and underscores (_). ' + . 'Also, the first character must be a letter.' + )); + } + } +} diff --git a/lib/internal/Magento/Framework/App/Scope/ValidatorInterface.php b/lib/internal/Magento/Framework/App/Scope/ValidatorInterface.php new file mode 100644 index 0000000000000..8063d61d8f5b2 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Scope/ValidatorInterface.php @@ -0,0 +1,22 @@ +_scopeResolvers = $scopeResolvers; } diff --git a/lib/internal/Magento/Framework/App/ScopeTreeProviderInterface.php b/lib/internal/Magento/Framework/App/ScopeTreeProviderInterface.php index 49ff873e52bbb..0457d5b4d54b5 100644 --- a/lib/internal/Magento/Framework/App/ScopeTreeProviderInterface.php +++ b/lib/internal/Magento/Framework/App/ScopeTreeProviderInterface.php @@ -1,6 +1,6 @@ getDir($this->projectRoot); $isSubDir = false !== strpos($setupDir . '/', $this->docRoot . '/'); + // Setup is not accessible from pub folder + $setupDir = rtrim($setupDir, '/'); + $lastOccurrence = strrpos($setupDir, '/pub/setup'); + + if (false !== $lastOccurrence) { + $setupDir = substr_replace($setupDir, '/setup', $lastOccurrence, strlen('/pub/setup')); + } + return $isSubDir && realpath($setupDir); } diff --git a/lib/internal/Magento/Framework/App/Shell.php b/lib/internal/Magento/Framework/App/Shell.php index 39157919f221e..9723f26dfe3f4 100644 --- a/lib/internal/Magento/Framework/App/Shell.php +++ b/lib/internal/Magento/Framework/App/Shell.php @@ -1,6 +1,6 @@ checkAreaCode($code); + if (isset($this->_areaCode)) { throw new \Magento\Framework\Exception\LocalizedException( new \Magento\Framework\Phrase('Area code is already set') @@ -164,6 +171,8 @@ public function isAreaCodeEmulated() */ public function emulateAreaCode($areaCode, $callback, $params = []) { + $this->checkAreaCode($areaCode); + $currentArea = $this->_areaCode; $this->_areaCode = $areaCode; $this->_isAreaCodeEmulated = true; @@ -178,4 +187,40 @@ public function emulateAreaCode($areaCode, $callback, $params = []) $this->_isAreaCodeEmulated = false; return $result; } + + /** + * Check that area code exists + * + * @param string $areaCode + * @throws \Magento\Framework\Exception\LocalizedException + * @return void + */ + private function checkAreaCode($areaCode) + { + $areaCodes = array_merge( + [Area::AREA_GLOBAL], + $this->getAreaListInstance()->getCodes() + ); + + if (!in_array($areaCode, $areaCodes)) { + throw new \Magento\Framework\Exception\LocalizedException( + new \Magento\Framework\Phrase('Area code "%1" does not exist', [$areaCode]) + ); + } + } + + /** + * Get Instance of AreaList + * + * @return AreaList + * @deprecated + */ + private function getAreaListInstance() + { + if ($this->areaList === null) { + $this->areaList = ObjectManager::getInstance()->get(AreaList::class); + } + + return $this->areaList; + } } diff --git a/lib/internal/Magento/Framework/App/State/CleanupFiles.php b/lib/internal/Magento/Framework/App/State/CleanupFiles.php index 8e70342cb8dc4..05c00dea8ae3b 100644 --- a/lib/internal/Magento/Framework/App/State/CleanupFiles.php +++ b/lib/internal/Magento/Framework/App/State/CleanupFiles.php @@ -1,6 +1,6 @@ emptyDir(DirectoryList::GENERATION), $this->emptyDir(DirectoryList::DI)); + return array_merge( + $this->emptyDir(DirectoryList::GENERATED_CODE), + $this->emptyDir(DirectoryList::GENERATED_METADATA) + ); } /** diff --git a/lib/internal/Magento/Framework/App/StaticResource.php b/lib/internal/Magento/Framework/App/StaticResource.php index beeeb716260e9..fb33cf765f6fe 100644 --- a/lib/internal/Magento/Framework/App/StaticResource.php +++ b/lib/internal/Magento/Framework/App/StaticResource.php @@ -1,6 +1,6 @@ setMethods(['setRefererOrBaseUrl']) ->disableOriginalConstructor() ->getMock(); - $this->redirectFactory = $this->getMockBuilder(\Magento\Backend\Model\View\Result\RedirectFactory::class) + $this->redirectFactory = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class) ->setMethods(['create']) ->disableOriginalConstructor() ->getMock(); diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Action/ActionTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Action/ActionTest.php index cb9c427816d23..c34a2c943edcd 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Action/ActionTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Action/ActionTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/app/etc/custom/config.xml b/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/app/etc/custom/config.xml index 2def17182e59f..622b238d90f33 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/app/etc/custom/config.xml +++ b/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/app/etc/custom/config.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/di.xml b/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/di.xml index 2def17182e59f..622b238d90f33 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/di.xml +++ b/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/some_config/di.xml b/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/some_config/di.xml index 2def17182e59f..622b238d90f33 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/some_config/di.xml +++ b/lib/internal/Magento/Framework/App/Test/Unit/Arguments/FileResolver/_files/primary/app/etc/some_config/di.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/BootstrapTest.php b/lib/internal/Magento/Framework/App/Test/Unit/BootstrapTest.php index 66564cc7f2120..a218055d8b32a 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/BootstrapTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/BootstrapTest.php @@ -1,6 +1,6 @@ cacheState = $this->getMockForAbstractClass(\Magento\Framework\App\Cache\StateInterface::class); $this->frontendPool = $this->getMock(\Magento\Framework\App\Cache\Type\FrontendPool::class, [], [], '', false); + $this->tagResolver = $this->getMock(\Magento\Framework\App\Cache\Tag\Resolver::class, [], [], '', false); + $this->plugin = new \Magento\Framework\App\Cache\FlushCacheByTags( $this->frontendPool, $this->cacheState, - ['test'] + ['test'], + $this->tagResolver ); } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/FactoryTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/FactoryTest.php index 77a0d7e664e91..85bdcc4b16639 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/FactoryTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Frontend/FactoryTest.php @@ -1,6 +1,6 @@ strategyFactory = $this->getMock( + \Magento\Framework\App\Cache\Tag\Strategy\Factory::class, + [], + [], + '', + false + ); + + $this->strategy = $this->getMockForAbstractClass(\Magento\Framework\App\Cache\Tag\StrategyInterface::class); + + $this->strategyFactory->expects($this->any()) + ->method('getStrategy') + ->willReturn($this->strategy); + + $this->model = new Resolver($this->strategyFactory); + } + + public function testGetTagsForNotObject() + { + $this->setExpectedException(\InvalidArgumentException::class, 'Provided argument is not an object'); + $this->model->getTags('some scalar'); + } + + public function testGetTagsForObject() + { + $strategyReturnValue = ['test tag']; + $object = new \StdClass; + $this->strategy->expects($this->once()) + ->method('getTags') + ->with($object) + ->willReturn($strategyReturnValue); + + $this->assertEquals($strategyReturnValue, $this->model->getTags($object)); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/DummyTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/DummyTest.php new file mode 100644 index 0000000000000..494c79f590105 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/DummyTest.php @@ -0,0 +1,36 @@ +model = new Dummy(); + } + + public function testGetTagsWithScalar() + { + $this->setExpectedException(\InvalidArgumentException::class, 'Provided argument is not an object'); + $this->model->getTags('scalar'); + } + + public function testGetTagsWithObject() + { + $emptyArray = []; + + $this->assertEquals($emptyArray, $this->model->getTags(new \StdClass)); + + $identityInterface = $this->getMockForAbstractClass(\Magento\Framework\DataObject\IdentityInterface::class); + $this->assertEquals($emptyArray, $this->model->getTags($identityInterface)); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/FactoryTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/FactoryTest.php new file mode 100644 index 0000000000000..059f86fb3de7c --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/FactoryTest.php @@ -0,0 +1,86 @@ +identifierStrategy = $this->getMock( + \Magento\Framework\App\Cache\Tag\Strategy\Identifier::class, + [], + [], + '', + false + ); + + $this->dummyStrategy = $this->getMock( + \Magento\Framework\App\Cache\Tag\Strategy\Dummy::class, + [], + [], + '', + false + ); + + $this->customStrategy = $this->getMockForAbstractClass( + \Magento\Framework\App\Cache\Tag\StrategyInterface::class + ); + + $this->model = new Factory( + $this->identifierStrategy, + $this->dummyStrategy, + ['PDO' => $this->customStrategy] + ); + } + + public function testGetStrategyWithScalar() + { + $this->setExpectedException(\InvalidArgumentException::class, 'Provided argument is not an object'); + $this->model->getStrategy('some scalar'); + } + + public function testGetStrategyWithObject() + { + $this->assertEquals($this->dummyStrategy, $this->model->getStrategy(new \StdClass)); + } + + public function testGetStrategyWithIdentityInterface() + { + $object = $this->getMockForAbstractClass(\Magento\Framework\DataObject\IdentityInterface::class); + + $this->assertEquals($this->identifierStrategy, $this->model->getStrategy($object)); + } + + public function testGetStrategyForCustomClass() + { + $object = $this->getMockForAbstractClass('\PDO', [], '', false, false, false, []); + + $this->assertEquals($this->customStrategy, $this->model->getStrategy($object)); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/IdentifierTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/IdentifierTest.php new file mode 100644 index 0000000000000..0f2e434f4084f --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Tag/Strategy/IdentifierTest.php @@ -0,0 +1,46 @@ +model = new Identifier; + } + + public function testGetWithScalar() + { + $this->setExpectedException(\InvalidArgumentException::class, 'Provided argument is not an object'); + $this->model->getTags('scalar'); + } + + public function testGetTagsWithObject() + { + $this->assertEquals([], $this->model->getTags(new \StdClass)); + } + + public function testGetTagsWithIdentityInterface() + { + $object = $this->getMockForAbstractClass(\Magento\Framework\DataObject\IdentityInterface::class); + + $identities = ['id1', 'id2']; + + $object->expects($this->once()) + ->method('getIdentities') + ->willReturn($identities); + + $this->assertEquals($identities, $this->model->getTags($object)); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Type/AccessProxyTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Type/AccessProxyTest.php index 5461f510f6256..fbdb850bbc0d1 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Type/AccessProxyTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Type/AccessProxyTest.php @@ -1,6 +1,6 @@ _typesArray = [ @@ -85,6 +91,7 @@ protected function setUp() '', false ); + $this->serializerMock = $this->getMock(SerializerInterface::class); $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->_typeList = $objectHelper->getObject( @@ -93,7 +100,8 @@ protected function setUp() 'config' => $this->_config, 'cacheState' => $cacheState, 'factory' => $factory, - 'cache' => $this->_cache + 'cache' => $this->_cache, + 'serializer' => $this->serializerMock, ] ); } @@ -118,8 +126,12 @@ public function testGetInvalidated() { $expectation = [self::TYPE_KEY => $this->_getPreparedType()]; $this->_cache->expects($this->once())->method('load')->with(TypeList::INVALIDATED_TYPES)->will( - $this->returnValue(serialize($this->_typesArray)) + $this->returnValue('serializedData') ); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn($this->_typesArray); $this->assertEquals($expectation, $this->_typeList->getInvalidated()); } @@ -132,8 +144,12 @@ public function testInvalidate() $expectedInvalidated = [ self::TYPE_KEY => 1, ]; + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($expectedInvalidated) + ->willReturn('serializedData'); $this->_cache->expects($this->once())->method('save')->with( - serialize($expectedInvalidated), + 'serializedData', TypeList::INVALIDATED_TYPES ); $this->_typeList->invalidate(self::TYPE_KEY); @@ -147,8 +163,12 @@ public function testInvalidateList() $expectedInvalidated = [ self::TYPE_KEY => 1, ]; + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($expectedInvalidated) + ->willReturn('serializedData'); $this->_cache->expects($this->once())->method('save')->with( - serialize($expectedInvalidated), + 'serializedData', TypeList::INVALIDATED_TYPES ); $this->_typeList->invalidate([self::TYPE_KEY]); @@ -156,15 +176,23 @@ public function testInvalidateList() public function testCleanType() { + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn($this->_typesArray); $this->_cache->expects($this->once())->method('load')->with(TypeList::INVALIDATED_TYPES)->will( - $this->returnValue(serialize($this->_typesArray)) + $this->returnValue('serializedData') ); $this->_config->expects($this->once())->method('getType')->with(self::TYPE_KEY)->will( $this->returnValue(['instance' => self::CACHE_TYPE]) ); unset($this->_typesArray[self::TYPE_KEY]); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($this->_typesArray) + ->willReturn('serializedData'); $this->_cache->expects($this->once())->method('save')->with( - serialize($this->_typesArray), + 'serializedData', TypeList::INVALIDATED_TYPES ); $this->_typeList->cleanType(self::TYPE_KEY); diff --git a/lib/internal/Magento/Framework/App/Test/Unit/CacheTest.php b/lib/internal/Magento/Framework/App/Test/Unit/CacheTest.php index 275d74efd9416..75a2dc4d4854b 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/CacheTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/CacheTest.php @@ -1,6 +1,6 @@ scopeCodeResolverMock = $this->getMockBuilder(ScopeCodeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new ConfigPathResolver( + $this->scopeCodeResolverMock + ); + } + + /** + * @param string $path + * @param string $scope + * @param string $scopeCode + * @param string $type + * @param string $expected + * @dataProvider resolveDataProvider + */ + public function testResolve($path, $scope, $scopeCode, $type, $expected) + { + $this->scopeCodeResolverMock->expects($this->any()) + ->method('resolve') + ->willReturn($scopeCode ? $scopeCode : 'test_code'); + + $this->assertSame($expected, $this->model->resolve($path, $scope, $scopeCode, $type)); + } + + public function resolveDataProvider() + { + return [ + ['/test/test/test/', 'default', null, null, 'default/test/test/test'], + ['test/test/test', 'default', null, 'system', 'system/default/test/test/test'], + ['test/test/test', 'website', 'base', 'system', 'system/websites/base/test/test/test'], + ['test/test/test', 'websites', null, 'system', 'system/websites/test_code/test/test/test'], + ]; + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/ConfigSourceAggregatedTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/ConfigSourceAggregatedTest.php new file mode 100644 index 0000000000000..7e9d1e8616a81 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/ConfigSourceAggregatedTest.php @@ -0,0 +1,69 @@ +sourceMock = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + $this->sourceMockTwo = $this->getMockBuilder(ConfigSourceInterface::class) + ->getMockForAbstractClass(); + + $sources = [ + [ + 'source' => $this->sourceMockTwo, + 'sortOrder' => 100 + ], + [ + 'source' => $this->sourceMock, + 'sortOrder' => 10 + ], + + ]; + + $this->source = new ConfigSourceAggregated($sources); + } + + public function testGet() + { + $path = 'path'; + $this->sourceMock->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value1', 'test' => false]); + $this->sourceMockTwo->expects($this->once()) + ->method('get') + ->with($path) + ->willReturn(['key' => 'value2']); + $this->assertEquals( + [ + 'test' => false, + 'key' => 'value2' + ], + $this->source->get($path) + ); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Data/ProcessorFactoryTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/Data/ProcessorFactoryTest.php index 2de8206f2e1ab..e171dae2b5643 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Data/ProcessorFactoryTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Data/ProcessorFactoryTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/config.xsd b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/config.xsd index 62a9fdc20aa90..e60063522c757 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/config.xsd +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/config.xsd @@ -1,10 +1,10 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/converted_config.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/converted_config.php index 17f7f9bbbdce0..bcc119b33bdf5 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/converted_config.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/converted_config.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config2.xml b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config2.xml index abaed7a879f2b..0016210cd149d 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config2.xml +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config2.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config_merged.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config_merged.php index f9876e7ba8cae..69b85fedbfc6e 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config_merged.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/initial_config_merged.php @@ -1,6 +1,6 @@ [], 'metadata' => []]; diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/invalidConfigXmlArray.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/invalidConfigXmlArray.php index b947757146a13..f4b31f8ee52cc 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/invalidConfigXmlArray.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/invalidConfigXmlArray.php @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/valid_config.xml b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/valid_config.xml index 076ff2f542a1a..a4e7b80295b81 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/valid_config.xml +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Initial/_files/valid_config.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialConfigSourceTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialConfigSourceTest.php new file mode 100644 index 0000000000000..cb92ac4ab405a --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialConfigSourceTest.php @@ -0,0 +1,54 @@ +reader = $this->getMockBuilder(Reader::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configType = 'configType'; + $this->fileKey = 'file.php'; + $this->source = new InitialConfigSource($this->reader, $this->configType, $this->fileKey); + } + + public function testGet() + { + $path = 'path'; + $this->reader->expects($this->once()) + ->method('load') + ->with($this->fileKey) + ->willReturn([$this->configType => [$path => 'value']]); + $this->assertEquals('value', $this->source->get($path)); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialTest.php index ce85753bedab5..da42c0fadf225 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/InitialTest.php @@ -1,65 +1,74 @@ [ + 'default' => ['key' => 'default_value'], + 'stores' => ['default' => ['key' => 'store_value']], + 'websites' => ['default' => ['key' => 'website_value']], + ], + 'metadata' => ['metadata'], + ]; protected function setUp() { - $this->_initialReaderMock = - $this->getMock(\Magento\Framework\App\Config\Initial\Reader::class, [], [], '', false); - $this->_configCacheMock = - $this->getMock(\Magento\Framework\App\Cache\Type\Config::class, [], [], '', false); - $serializedData = serialize( + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->cacheMock = $this->getMock( + \Magento\Framework\App\Cache\Type\Config::class, + [], + [], + '', + false + ); + $this->cacheMock->expects($this->any()) + ->method('load') + ->with('initial_config') + ->willReturn(json_encode($this->data)); + $serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); + $serializerMock->method('unserialize') + ->willReturn($this->data); + + $this->config = $this->objectManager->getObject( + \Magento\Framework\App\Config\Initial::class, [ - 'data' => [ - 'default' => ['key' => 'default_value'], - 'stores' => ['default' => ['key' => 'store_value']], - 'websites' => ['default' => ['key' => 'website_value']], - ], - 'metadata' => ['metadata'], + 'cache' => $this->cacheMock, + 'serializer' => $serializerMock, ] ); - $this->_configCacheMock->expects( - $this->any() - )->method( - 'load' - )->with( - 'initial_config' - )->will( - $this->returnValue($serializedData) - ); - - $this->_model = new \Magento\Framework\App\Config\Initial($this->_initialReaderMock, $this->_configCacheMock); } /** - * @dataProvider getDataDataProvider - * * @param string $scope - * @param array $expectedResult + * @param array $expected + * @dataProvider getDataDataProvider */ - public function testGetData($scope, $expectedResult) + public function testGetData($scope, $expected) { - $this->assertEquals($expectedResult, $this->_model->getData($scope)); + $this->assertEquals($expected, $this->config->getData($scope)); } public function getDataDataProvider() @@ -73,7 +82,6 @@ public function getDataDataProvider() public function testGetMetadata() { - $expectedResult = ['metadata']; - $this->assertEquals($expectedResult, $this->_model->getMetadata()); + $this->assertEquals(['metadata'], $this->config->getMetadata()); } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataConfigTypeProcessorTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataConfigTypeProcessorTest.php new file mode 100644 index 0000000000000..4fe2e533b3864 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataConfigTypeProcessorTest.php @@ -0,0 +1,79 @@ +_modelPoolMock = $this->getMock( + \Magento\Framework\App\Config\Data\ProcessorFactory::class, + [], + [], + '', + false + ); + $this->_initialConfigMock = $this->getMock(\Magento\Framework\App\Config\Initial::class, [], [], '', false); + $this->_backendModelMock = $this->getMock(\Magento\Framework\App\Config\Data\ProcessorInterface::class); + $this->_initialConfigMock->expects( + $this->any() + )->method( + 'getMetadata' + )->will( + $this->returnValue(['some/config/path' => ['backendModel' => 'Custom_Backend_Model']]) + ); + $this->_model = new \Magento\Framework\App\Config\MetadataConfigTypeProcessor( + $this->_modelPoolMock, + $this->_initialConfigMock + ); + } + + public function testProcess() + { + $this->_modelPoolMock->expects( + $this->once() + )->method( + 'get' + )->with( + 'Custom_Backend_Model' + )->will( + $this->returnValue($this->_backendModelMock) + ); + $this->_backendModelMock->expects( + $this->once() + )->method( + 'processValue' + )->with( + 'value' + )->will( + $this->returnValue('processed_value') + ); + $data = ['default' => [ 'some' => ['config' => ['path' => 'value']], 'active' => 1]]; + $expectedResult = $data; + $expectedResult['default']['some']['config']['path'] = 'processed_value'; + $this->assertEquals($expectedResult, $this->_model->process($data)); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataProcessorTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataProcessorTest.php index 7db4ae150ce3c..0a1544e492efe 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataProcessorTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataProcessorTest.php @@ -1,50 +1,61 @@ _modelPoolMock = $this->getMock( - \Magento\Framework\App\Config\Data\ProcessorFactory::class, - [], - [], - '', - false - ); - $this->_initialConfigMock = $this->getMock(\Magento\Framework\App\Config\Initial::class, [], [], '', false); - $this->_backendModelMock = $this->getMock(\Magento\Framework\App\Config\Data\ProcessorInterface::class); - $this->_initialConfigMock->expects( - $this->any() - )->method( - 'getMetadata' - )->will( - $this->returnValue(['some/config/path' => ['backendModel' => 'Custom_Backend_Model']]) - ); + $this->_modelPoolMock = $this->getMockBuilder(ProcessorFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->_initialConfigMock = $this->getMockBuilder(Initial::class) + ->disableOriginalConstructor() + ->getMock(); + $this->_backendModelMock = $this->getMockBuilder(ProcessorInterface::class) + ->getMockForAbstractClass(); + + $this->_initialConfigMock->expects($this->any()) + ->method('getMetadata') + ->willReturn( + ['some/config/path' => ['backendModel' => 'Custom_Backend_Model']] + ); + $this->_model = new \Magento\Framework\App\Config\MetadataProcessor( $this->_modelPoolMock, $this->_initialConfigMock @@ -53,24 +64,15 @@ protected function setUp() public function testProcess() { - $this->_modelPoolMock->expects( - $this->once() - )->method( - 'get' - )->with( - 'Custom_Backend_Model' - )->will( - $this->returnValue($this->_backendModelMock) - ); - $this->_backendModelMock->expects( - $this->once() - )->method( - 'processValue' - )->with( - 'value' - )->will( - $this->returnValue('processed_value') - ); + $this->_modelPoolMock->expects($this->once()) + ->method('get') + ->with('Custom_Backend_Model') + ->willReturn($this->_backendModelMock); + $this->_backendModelMock->expects($this->once()) + ->method('processValue') + ->with('value') + ->willReturn('processed_value'); + $data = ['some' => ['config' => ['path' => 'value']], 'active' => 1]; $expectedResult = $data; $expectedResult['some']['config']['path'] = 'processed_value'; diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/PreProcessorCompositeTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/PreProcessorCompositeTest.php new file mode 100644 index 0000000000000..6a94d1e2be723 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/PreProcessorCompositeTest.php @@ -0,0 +1,40 @@ +preProcessorMock = $this->getMockBuilder(PreProcessorInterface::class) + ->getMockForAbstractClass(); + + $this->model = new PreProcessorComposite([$this->preProcessorMock]); + } + + public function testProcess() + { + $this->preProcessorMock->expects($this->once()) + ->method('process') + ->with(['test' => 'data']) + ->willReturn(['test' => 'data2']); + + $this->assertSame(['test' => 'data2'], $this->model->process(['test' => 'data'])); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Scope/ConverterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/Scope/ConverterTest.php index c3818a4e10971..50cc44c1354d6 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Scope/ConverterTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Scope/ConverterTest.php @@ -1,6 +1,6 @@ scopeResolverPoolMock = $this->getMockBuilder(ScopeResolverPool::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new Validator( + $this->scopeResolverPoolMock + ); + } + + public function testIsValid() + { + $scope = 'not_default_scope'; + $scopeCode = 'not_exist_scope_code'; + + $scopeResolver = $this->getMockBuilder(ScopeResolverInterface::class) + ->getMockForAbstractClass(); + $scopeObject = $this->getMockBuilder(ScopeInterface::class) + ->getMockForAbstractClass(); + $scopeResolver->expects($this->once()) + ->method('getScope') + ->with($scopeCode) + ->willReturn($scopeObject); + $this->scopeResolverPoolMock->expects($this->once()) + ->method('get') + ->with($scope) + ->willReturn($scopeResolver); + + $this->assertTrue($this->model->isValid($scope, $scopeCode)); + } + + public function testIsValidDefault() + { + $this->assertTrue($this->model->isValid(ScopeConfigInterface::SCOPE_TYPE_DEFAULT)); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage The "default" scope can't include a scope code. Try again without entering a scope + */ + public function testNotEmptyScopeCodeForDefaultScope() + { + $this->model->isValid(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 'some_code'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Enter a scope before proceeding. + */ + public function testEmptyScope() + { + $this->model->isValid('', 'some_code'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Enter a scope code before proceeding. + */ + public function testEmptyScopeCode() + { + $this->model->isValid('not_default_scope', ''); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage The scope code can include only lowercase letters (a-z), numbers (0-9) and underscores + */ + public function testWrongScopeCodeFormat() + { + $this->model->isValid('not_default_scope', '123'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage The "not_default_scope" value doesn't exist. Enter another value. + */ + public function testScopeNotExist() + { + $scope = 'not_default_scope'; + $this->scopeResolverPoolMock->expects($this->once()) + ->method('get') + ->with($scope) + ->willThrowException(new \InvalidArgumentException()); + + $this->model->isValid($scope, 'scope_code'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage The "not_exist_scope_code" value doesn't exist. Enter another value. + */ + public function testScopeCodeNotExist() + { + $scope = 'not_default_scope'; + $scopeCode = 'not_exist_scope_code'; + + $scopeResolver = $this->getMockBuilder(ScopeResolverInterface::class) + ->getMockForAbstractClass(); + $scopeResolver->expects($this->once()) + ->method('getScope') + ->with($scopeCode) + ->willThrowException(new NoSuchEntityException()); + $this->scopeResolverPoolMock->expects($this->once()) + ->method('get') + ->with($scope) + ->willReturn($scopeResolver); + + $this->model->isValid($scope, $scopeCode); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/ScopeCodeResolverTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/ScopeCodeResolverTest.php new file mode 100644 index 0000000000000..559abea09d39a --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/ScopeCodeResolverTest.php @@ -0,0 +1,68 @@ +scopeResolverPool = $this->getMockBuilder(ScopeResolverPool::class) + ->disableOriginalConstructor() + ->getMock(); + $this->scopeResolver = $this->getMockBuilder(ScopeResolverInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->scope = $this->getMockBuilder(ScopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->scopeCodeResolver = new ScopeCodeResolver($this->scopeResolverPool); + } + + public function testResolve() + { + $scopeType = 'website'; + $scopeCode = 'myWebsite'; + $scopeId = 4; + $this->scopeResolverPool->expects($this->once()) + ->method('get') + ->with($scopeType) + ->willReturn($this->scopeResolver); + $this->scopeResolver->expects($this->once()) + ->method('getScope') + ->with($scopeId) + ->willReturn($this->scope); + $this->scope->expects($this->once()) + ->method('getCode') + ->willReturn($scopeCode); + $this->assertEquals($scopeCode, $this->scopeCodeResolver->resolve($scopeType, $scopeId)); + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/ScopePoolTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/ScopePoolTest.php deleted file mode 100644 index 6c9ae8a09a77d..0000000000000 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/ScopePoolTest.php +++ /dev/null @@ -1,168 +0,0 @@ -_readerPool = $this->getMockForAbstractClass(ReaderPoolInterface::class); - $this->_reader = $this->getMockForAbstractClass(ReaderInterface::class); - $this->_dataFactory = $this->getMockBuilder( - \Magento\Framework\App\Config\DataFactory::class - )->disableOriginalConstructor()->getMock(); - $this->_cache = $this->getMock(\Magento\Framework\Cache\FrontendInterface::class); - $this->_object = $helper->getObject( - \Magento\Framework\App\Config\ScopePool::class, - [ - 'readerPool' => $this->_readerPool, - 'dataFactory' => $this->_dataFactory, - 'cache' => $this->_cache, - 'cacheId' => 'test_cache_id' - ] - ); - - $requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) - ->disableOriginalConstructor() - ->setMethods( - [ - 'getBasePath', - 'getModuleName', - 'setModuleName', - 'getActionName', - 'setActionName', - 'getParam', - 'getParams', - 'setParams', - 'getCookie', - 'isSecure', - 'getServer', - 'getHttpHost' - ] - )->getMock(); - $reflection = new \ReflectionClass(get_class($this->_object)); - $reflectionProperty = $reflection->getProperty('request'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->_object, $requestMock); - $requestMock->expects($this->any()) - ->method('getBasePath') - ->willReturn('baseUrl'); - } - - /** - * @dataProvider getScopeDataProvider - * - * @param string $scopeType - * @param string $scope - * @param array $data - * @param string|null $cachedData - */ - public function testGetScope($scopeType, $scope, array $data, $cachedData) - { - $scopeCode = $scope instanceof \Magento\Framework\App\ScopeInterface ? $scope->getCode() : $scope; - $cacheKey = "test_cache_id|{$scopeType}|{$scopeCode}|baseUrl"; - - $this->_readerPool->expects( - $this->any() - )->method( - 'getReader' - )->with( - $scopeType - )->will( - $this->returnValue($this->_reader) - ); - $this->_cache->expects($this->once())->method('load')->with($cacheKey)->will($this->returnValue($cachedData)); - - if (!$cachedData) { - $this->_reader->expects($this->once())->method('read')->with('testScope')->will($this->returnValue($data)); - $this->_cache->expects( - $this->once() - )->method( - 'save' - )->with( - serialize($data), - $cacheKey, - [\Magento\Framework\App\Config\ScopePool::CACHE_TAG] - ); - } - - $configData = $this->getMockBuilder(\Magento\Framework\App\Config\Data::class) - ->disableOriginalConstructor() - ->getMock(); - $this->_dataFactory->expects( - $this->once() - )->method( - 'create' - )->with( - ['data' => $data] - )->will( - $this->returnValue($configData) - ); - $this->assertInstanceOf( - \Magento\Framework\App\Config\DataInterface::class, - $this->_object->getScope($scopeType, $scope) - ); - - // second call to check caching - $this->assertInstanceOf( - \Magento\Framework\App\Config\DataInterface::class, - $this->_object->getScope($scopeType, $scope) - ); - } - - public function getScopeDataProvider() - { - $baseScope = $this->getMockForAbstractClass(\Magento\Framework\App\ScopeInterface::class); - $baseScope->expects($this->any())->method('getCode')->will($this->returnValue('testScope')); - return [ - ['scopeType1', 'testScope', ['key' => 'value'], null], - ['scopeType2', 'testScope', ['key' => 'value'], serialize(['key' => 'value'])], - ['scopeType1', $baseScope, ['key' => 'value'], null] - ]; - } - - public function testClean() - { - $this->_cache->expects( - $this->once() - )->method( - 'clean' - )->with( - \Zend_Cache::CLEANING_MODE_MATCHING_TAG, - [\Magento\Framework\App\Config\ScopePool::CACHE_TAG] - ); - $this->_object->clean('testScope'); - } -} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php index 16304bc304171..42c24a2c9dce6 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/_files/invalidRoutesXmlArray.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/_files/invalidRoutesXmlArray.php index 5f716001548d4..e73d43d360735 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Config/_files/invalidRoutesXmlArray.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/_files/invalidRoutesXmlArray.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ConfigTest.php new file mode 100644 index 0000000000000..b464bf75cac52 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/ConfigTest.php @@ -0,0 +1,83 @@ +scopeCodeResolver = $this->getMockBuilder(ScopeCodeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configType = $this->getMockBuilder(ConfigTypeInterface::class) + ->getMockForAbstractClass(); + $this->scope = $this->getMockBuilder(ScopeInterface::class) + ->getMockForAbstractClass(); + + $this->appConfig = new Config($this->scopeCodeResolver, ['system' => $this->configType]); + } + + /** + * @param string $scope + * @param string|null $scopeCode + * + * @dataProvider getValueDataProvider + * @return void + */ + public function testGetValue($scope, $scopeCode = null) + { + $path = 'path'; + if (!is_string($scope)) { + $this->scopeCodeResolver->expects($this->once()) + ->method('resolve') + ->with('stores', $scopeCode) + ->willReturn('myStore'); + } elseif (!$scopeCode) { + $this->scope->expects($this->once()) + ->method('getCode') + ->willReturn('myWebsite'); + } + $this->configType->expects($this->once()) + ->method('get') + ->with($scope =='store' ? 'stores/path' : 'websites/myWebsite/path') + ->willReturn(true); + + $this->assertTrue($this->appConfig->getValue($path, $scope, $scopeCode ?: $this->scope)); + } + + public function getValueDataProvider() + { + return [ + ['store', 1], + ['website'], + ]; + } +} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Console/CommandListTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Console/CommandListTest.php index 6cd222d3876dc..b53f3e0675232 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Console/CommandListTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Console/CommandListTest.php @@ -1,6 +1,6 @@ expects($this->any()) ->method('getPaths') ->willReturn(['configKeyOne' => 'config.php', 'configKeyTwo' => 'env.php']); + $this->configFilePool + ->expects($this->any()) + ->method('getInitialFilePools') + ->willReturn([]); } public function testGetFile() @@ -103,6 +107,7 @@ public function testCustomLoad($file, $expected) $configFilePool = $this->getMock(\Magento\Framework\Config\File\ConfigFilePool::class, [], [], '', false); $configFilePool->expects($this->any())->method('getPaths')->willReturn([$file]); $configFilePool->expects($this->any())->method('getPath')->willReturn($file); + $configFilePool->expects($this->any())->method('getInitialFilePools')->willReturn([]); $object = new Reader($this->dirList, $this->driverPool, $configFilePool, $file); $this->assertSame($expected, $object->load($file)); } @@ -130,6 +135,9 @@ public function testMerging() ->expects($this->any()) ->method('getPath') ->will($this->returnValueMap($files)); + $configFilePool->expects($this->any()) + ->method('getInitialFilePools') + ->willReturn([]); $configFilePool ->expects($this->any()) ->method('getPaths') @@ -150,6 +158,9 @@ public function testMergingWithDuplicateEndValues() ->expects($this->any()) ->method('getPath') ->will($this->returnValueMap($files)); + $configFilePool->expects($this->any()) + ->method('getInitialFilePools') + ->willReturn([]); $configFilePool ->expects($this->any()) ->method('getPaths') diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php index a9b5bc04a1276..9f6894c0a6835 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php @@ -1,19 +1,136 @@ assertEquals("format($data)); + $this->assertEquals($expectedResult, $formatter->format($data, $comments)); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function formatWithCommentDataProvider() + { + $array = [ + 'ns1' => [ + 's1' => [ + 's11', + 's12' + ], + 's2' => [ + 's21', + 's22' + ], + ], + 'ns2' => [ + 's1' => [ + 's11' + ], + ], + 'ns3' => 'just text', + 'ns4' => 'just text' + ]; + $comments1 = ['ns2' => 'comment for namespace 2']; + $comments2 = [ + 'ns1' => 'comment for\' namespace 1', + 'ns2' => "comment for namespace 2.\nNext comment for' namespace 2", + 'ns3' => 'comment for" namespace 3', + 'ns4' => 'comment for namespace 4', + 'ns5' => 'comment for unexisted namespace 5', + ]; + $expectedResult1 = << + array ( + 's1' => + array ( + 0 => 's11', + 1 => 's12', + ), + 's2' => + array ( + 0 => 's21', + 1 => 's22', + ), + ), + /** + * comment for namespace 2 + */ + 'ns2' => + array ( + 's1' => + array ( + 0 => 's11', + ), + ), + 'ns3' => 'just text', + 'ns4' => 'just text' +); + +TEXT; + $expectedResult2 = << + array ( + 's1' => + array ( + 0 => 's11', + 1 => 's12', + ), + 's2' => + array ( + 0 => 's21', + 1 => 's22', + ), + ), + /** + * comment for namespace 2. + * Next comment for' namespace 2 + */ + 'ns2' => + array ( + 's1' => + array ( + 0 => 's11', + ), + ), + /** + * comment for" namespace 3 + */ + 'ns3' => 'just text', + /** + * comment for namespace 4 + */ + 'ns4' => 'just text' +); + +TEXT; + return [ + ['string', [], " 'test_conf.php', - 'test_key' => 'test2_conf.php' + ConfigFilePool::APP_CONFIG => 'config.php' ]; $testSetExisting = [ @@ -113,13 +117,14 @@ public function testSaveConfig() $this->deploymentConfig->expects($this->once())->method('resetData'); $this->configFilePool->expects($this->once())->method('getPaths')->willReturn($configFiles); $this->dirWrite->expects($this->any())->method('isExist')->willReturn(true); - $this->reader->expects($this->once())->method('load')->willReturn($testSetExisting[ConfigFilePool::APP_CONFIG]); + $this->reader->expects($this->once())->method('loadConfigFile') + ->willReturn($testSetExisting[ConfigFilePool::APP_CONFIG]); $this->formatter ->expects($this->once()) ->method('format') ->with($testSetExpected[ConfigFilePool::APP_CONFIG]) ->willReturn([]); - $this->dirWrite->expects($this->once())->method('writeFile')->with('test_conf.php', []); + $this->dirWrite->expects($this->once())->method('writeFile')->with('config.php', []); $this->object->saveConfig($testSetUpdate); } @@ -127,19 +132,7 @@ public function testSaveConfig() public function testSaveConfigOverride() { $configFiles = [ - ConfigFilePool::APP_CONFIG => 'test_conf.php', - 'test_key' => 'test2_conf.php' - ]; - - $testSetExisting = [ - ConfigFilePool::APP_CONFIG => [ - 'foo' => 'bar', - 'key' => 'value', - 'baz' => [ - 'test' => 'value', - 'test1' => 'value1' - ] - ], + ConfigFilePool::APP_CONFIG => 'config.php' ]; $testSetUpdate = [ @@ -152,8 +145,6 @@ public function testSaveConfigOverride() $testSetExpected = [ ConfigFilePool::APP_CONFIG => [ - 'foo' => 'bar', - 'key' => 'value', 'baz' => [ 'test' => 'value2', ] @@ -163,13 +154,12 @@ public function testSaveConfigOverride() $this->deploymentConfig->expects($this->once())->method('resetData'); $this->configFilePool->expects($this->once())->method('getPaths')->willReturn($configFiles); $this->dirWrite->expects($this->any())->method('isExist')->willReturn(true); - $this->reader->expects($this->once())->method('load')->willReturn($testSetExisting[ConfigFilePool::APP_CONFIG]); $this->formatter ->expects($this->once()) ->method('format') ->with($testSetExpected[ConfigFilePool::APP_CONFIG]) ->willReturn([]); - $this->dirWrite->expects($this->once())->method('writeFile')->with('test_conf.php', []); + $this->dirWrite->expects($this->once())->method('writeFile')->with('config.php', []); $this->object->saveConfig($testSetUpdate, true); } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/config.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/config.php index 3e80561c6eedd..304fce9ffd2a2 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/config.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/config.php @@ -1,6 +1,6 @@ [DirectoryList::PATH => '/baz']]); } + + public function testGetDefaultConfig() + { + $defaultConfig = DirectoryList::getDefaultConfig(); + + $this->assertArrayHasKey(DirectoryList::GENERATED, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::GENERATED_METADATA, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::GENERATED_CODE, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::ROOT, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::APP, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::CONFIG, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::LIB_INTERNAL, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::VAR_DIR, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::CACHE, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::LOG, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::SESSION, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::MEDIA, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::STATIC_VIEW, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::PUB, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::LIB_WEB, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::TMP, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::UPLOAD, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::TEMPLATE_MINIFICATION_DIR, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::TMP_MATERIALIZATION_DIR, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::SETUP, $defaultConfig); + $this->assertArrayHasKey(DirectoryList::COMPOSER_HOME, $defaultConfig); + } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/FrontClass.php b/lib/internal/Magento/Framework/App/Test/Unit/FrontClass.php index 0d020fb02c20f..0ee0e44fa3017 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/FrontClass.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/FrontClass.php @@ -2,7 +2,7 @@ /** * FrontClass model test class * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Test\Unit; diff --git a/lib/internal/Magento/Framework/App/Test/Unit/FrontControllerTest.php b/lib/internal/Magento/Framework/App/Test/Unit/FrontControllerTest.php index 5d77cbb8df0f2..918979c45c74e 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/FrontControllerTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/FrontControllerTest.php @@ -1,6 +1,6 @@ assertEquals(sha1(serialize($data)), $this->object->getVaryString()); } + + public function testToArray() + { + $newObject = new \Magento\Framework\App\Http\Context(['key' => 'value']); + + $newObject->setValue('key1', 'value1', 'default1'); + $newObject->setValue('key2', 'value2', 'default2'); + $this->assertEquals( + [ + 'data' => ['key' => 'value', 'key1' => 'value1', 'key2' => 'value2'], + 'default' => ['key1' => 'default1', 'key2' => 'default2'] + ], + $newObject->toArray() + ); + } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php b/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php index 618dd5e8dde06..5ebc453ef82f9 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/MaintenanceModeTest.php b/lib/internal/Magento/Framework/App/Test/Unit/MaintenanceModeTest.php index 3311e4d48e77f..97be7fdd34f9f 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/MaintenanceModeTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/MaintenanceModeTest.php @@ -1,6 +1,6 @@ _cacheFrontendMock = $this->getMock(\Magento\Framework\Cache\FrontendInterface::class); - $this->_configCache = new \Magento\Framework\App\ObjectManager\ConfigCache($this->_cacheFrontendMock); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->cacheFrontendMock = $this->getMock(\Magento\Framework\Cache\FrontendInterface::class); + $this->configCache = $objectManagerHelper->getObject( + \Magento\Framework\App\ObjectManager\ConfigCache::class, + ['cacheFrontend' => $this->cacheFrontendMock] + ); + + $this->serializerMock = $this->getMock(SerializerInterface::class); + $objectManagerHelper->setBackwardCompatibleProperty( + $this->configCache, + 'serializer', + $this->serializerMock + ); } protected function tearDown() { - unset($this->_configCache); + unset($this->configCache); } - public function testGet() + /** + * @dataProvider getDataProvider + */ + public function testGet($loadData, $expectedResult) { $key = 'key'; - $this->_cacheFrontendMock->expects( + $this->cacheFrontendMock->expects( $this->once() )->method( 'load' )->with( 'diConfig' . $key )->will( - $this->returnValue(false) + $this->returnValue($loadData) ); - $this->assertEquals(false, $this->_configCache->get($key)); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($loadData) + ->willReturn($expectedResult); + $this->assertEquals($expectedResult, $this->configCache->get($key)); + } + + public function getDataProvider() + { + return [ + [false, false], + ['serialized data', ['some data']], + ]; } public function testSave() { $key = 'key'; $config = ['config']; - $this->_cacheFrontendMock->expects($this->once())->method('save')->with(serialize($config), 'diConfig' . $key); - $this->_configCache->save($config, $key); + $serializedData = 'serialized data'; + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->willReturn($serializedData); + $this->cacheFrontendMock->expects($this->once())->method('save')->with($serializedData, 'diConfig' . $key); + $this->configCache->save($config, $key); } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/ConfigLoaderTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/ConfigLoaderTest.php index 5a0b4ae96f26c..53a25a29fde24 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/ConfigLoaderTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/ConfigLoaderTest.php @@ -1,6 +1,6 @@ _readerMock = $this->getMock( + $this->readerMock = $this->getMock( \Magento\Framework\ObjectManager\Config\Reader\Dom::class, [], [], @@ -40,7 +47,7 @@ protected function setUp() false ); - $this->_readerFactoryMock = $this->getMock( + $this->readerFactoryMock = $this->getMock( \Magento\Framework\ObjectManager\Config\Reader\DomFactory::class, ['create'], [], @@ -48,17 +55,29 @@ protected function setUp() false ); - $this->_readerFactoryMock->expects( + $this->readerFactoryMock->expects( $this->any() )->method( 'create' )->will( - $this->returnValue($this->_readerMock) + $this->returnValue($this->readerMock) ); - $this->_cacheMock = $this->getMock(\Magento\Framework\App\Cache\Type\Config::class, [], [], '', false); - $this->_model = new \Magento\Framework\App\ObjectManager\ConfigLoader( - $this->_cacheMock, $this->_readerFactoryMock + $this->cacheMock = $this->getMock(\Magento\Framework\App\Cache\Type\Config::class, [], [], '', false); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->object = $objectManagerHelper->getObject( + \Magento\Framework\App\ObjectManager\ConfigLoader::class, + [ + 'cache' => $this->cacheMock, + 'readerFactory' => $this->readerFactoryMock, + ] + ); + $this->serializerMock = $this->getMock(SerializerInterface::class); + $objectManagerHelper->setBackwardCompatibleProperty( + $this->object, + 'serializer', + $this->serializerMock ); } @@ -66,23 +85,28 @@ protected function setUp() * @param $area * @dataProvider loadDataProvider */ - public function testLoad($area) + public function testLoadNotCached($area) { $configData = ['some' => 'config', 'data' => 'value']; + $serializedData = 'serialized data'; - $this->_cacheMock->expects( - $this->once() - )->method( - 'load' - )->with( - $area . '::DiConfig' - )->will( - $this->returnValue(false) - ); + $this->cacheMock->expects($this->once()) + ->method('load') + ->with($area . '::DiConfig') + ->will($this->returnValue(false)); + + $this->cacheMock->expects($this->once()) + ->method('save') + ->with($serializedData); + $this->readerMock->expects($this->once())->method('read')->with($area)->will($this->returnValue($configData)); - $this->_readerMock->expects($this->once())->method('read')->with($area)->will($this->returnValue($configData)); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->willReturn($serializedData); - $this->assertEquals($configData, $this->_model->load($area)); + $this->serializerMock->expects($this->never())->method('unserialize'); + + $this->assertEquals($configData, $this->object->load($area)); } /** @@ -98,4 +122,23 @@ public function loadDataProvider() 'any area files' => ['any'] ]; } + + public function testLoadCached() + { + $configData = ['some' => 'config', 'data' => 'value']; + $serializedData = 'serialized data'; + + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn($serializedData); + $this->cacheMock->expects($this->never()) + ->method('save'); + $this->readerMock->expects($this->never())->method('read'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($serializedData) + ->willReturn($configData); + $this->serializerMock->expects($this->never())->method('serialize'); + $this->assertEquals($configData, $this->object->load('testArea')); + } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/Environment/CompiledTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/Environment/CompiledTest.php index 26ed18521ab48..8521a566f5b4d 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/Environment/CompiledTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/ObjectManager/Environment/CompiledTest.php @@ -1,6 +1,6 @@ getMock(\Zend\Http\Headers::class, [], [], '', false); $this->cacheMock = $this->getMock(\Magento\Framework\App\PageCache\Cache::class, [], [], '', false); $this->fullPageCacheMock = $this->getMock(\Magento\PageCache\Model\Cache\Type::class, [], [], '', false); - $this->identifierMock = - $this->getMock(\Magento\Framework\App\PageCache\Identifier::class, [], [], '', false); + $this->contextMock = $this->getMock(\Magento\Framework\App\Http\Context::class, [], [], '', false); + $this->httpResponseMock = $this->getMock(\Magento\Framework\App\Response\Http::class, [], [], '', false); + $this->identifierMock = $this->getMock(\Magento\Framework\App\PageCache\Identifier::class, [], [], '', false); $this->requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false); - $this->kernel = new Kernel($this->cacheMock, $this->identifierMock, $this->requestMock); + $this->serializer = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class, [], [], '', false); + $this->responseMock = $this->getMock(\Magento\Framework\App\Response\Http::class, [], [], '', false); + $this->contextFactoryMock = $this->getMock(ContextFactory::class, ['create'], [], '', false); + $this->httpFactoryMock = $this->getMock(HttpFactory::class, ['create'], [], '', false); + $this->responseMock->expects($this->any())->method('getHeaders')->willReturn($headersMock); + + $this->kernel = new Kernel( + $this->cacheMock, + $this->identifierMock, + $this->requestMock, + $this->contextMock, + $this->contextFactoryMock, + $this->httpFactoryMock, + $this->serializer + ); $reflection = new \ReflectionClass(\Magento\Framework\App\PageCache\Kernel::class); $reflectionProperty = $reflection->getProperty('fullPageCache'); $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($this->kernel, $this->fullPageCacheMock); + } - $this->responseMock = $this->getMockBuilder( - \Magento\Framework\App\Response\Http::class - )->setMethods( - ['getHeader', 'getHttpResponseCode', 'setNoCacheHeaders', 'clearHeader', '__wakeup'] - )->disableOriginalConstructor()->getMock(); + /** + * @dataProvider dataProviderForResultWithCachedData + * @param string $id + * @param mixed $cache + * @param bool $isGet + * @param bool $isHead + */ + public function testLoadWithCachedData($id, $cache, $isGet, $isHead) + { + $this->serializer->expects($this->once()) + ->method('unserialize') + ->willReturnCallback( + function ($value) { + return json_decode($value, true); + } + ); + + $this->contextFactoryMock + ->expects($this->once()) + ->method('create') + ->with( + [ + 'data' => ['context_data'], + 'default' => ['context_default_data'] + ] + ) + ->willReturn($this->contextMock); + + $this->httpFactoryMock + ->expects($this->once()) + ->method('create') + ->with(['context' => $this->contextMock]) + ->willReturn($this->httpResponseMock); + + $this->requestMock->expects($this->once())->method('isGet')->will($this->returnValue($isGet)); + $this->requestMock->expects($this->any())->method('isHead')->will($this->returnValue($isHead)); + $this->fullPageCacheMock->expects( + $this->any() + )->method( + 'load' + )->with( + $this->equalTo($id) + )->will( + $this->returnValue(json_encode($cache)) + ); + $this->httpResponseMock->expects($this->once())->method('setStatusCode')->with($cache['status_code']); + $this->httpResponseMock->expects($this->once())->method('setContent')->with($cache['content']); + $this->httpResponseMock->expects($this->once())->method('setHeader')->with(0, 'header', true); + $this->identifierMock->expects($this->any())->method('getValue')->will($this->returnValue($id)); + $this->assertEquals($this->httpResponseMock, $this->kernel->load()); + } + + /** + * @return array + */ + public function dataProviderForResultWithCachedData() + { + $data = [ + 'context' => [ + 'data' => ['context_data'], + 'default' => ['context_default_data'] + ], + 'status_code' => 'status_code', + 'content' => 'content', + 'headers' => ['header'] + ]; + + return [ + ['existing key', $data, true, false], + ['existing key', $data, false, true], + ]; } /** - * @dataProvider loadProvider - * @param mixed $expected + * @dataProvider dataProviderForResultWithoutCachedData * @param string $id * @param mixed $cache * @param bool $isGet * @param bool $isHead */ - public function testLoad($expected, $id, $cache, $isGet, $isHead) + public function testLoadWithoutCachedData($id, $cache, $isGet, $isHead) { $this->requestMock->expects($this->once())->method('isGet')->will($this->returnValue($isGet)); $this->requestMock->expects($this->any())->method('isHead')->will($this->returnValue($isHead)); @@ -70,31 +172,21 @@ public function testLoad($expected, $id, $cache, $isGet, $isHead) )->with( $this->equalTo($id) )->will( - $this->returnValue(serialize($cache)) + $this->returnValue(json_encode($cache)) ); $this->identifierMock->expects($this->any())->method('getValue')->will($this->returnValue($id)); - $this->assertEquals($expected, $this->kernel->load()); + $this->assertEquals(false, $this->kernel->load()); } /** * @return array */ - public function loadProvider() + public function dataProviderForResultWithoutCachedData() { - $data = [1, 2, 3]; return [ - [$data, 'existing key', $data, true, false], - [$data, 'existing key', $data, false, true], - [ - new \Magento\Framework\DataObject($data), - 'existing key', - new \Magento\Framework\DataObject($data), - true, - false - ], - [false, 'existing key', $data, false, false], - [false, 'non existing key', false, true, false], - [false, 'non existing key', false, false, false] + ['existing key', [], false, false], + ['non existing key', false, true, false], + ['non existing key', false, false, false] ]; } @@ -104,6 +196,14 @@ public function loadProvider() */ public function testProcessSaveCache($httpCode, $at) { + $this->serializer->expects($this->once()) + ->method('serialize') + ->willReturnCallback( + function ($value) { + return json_encode($value); + } + ); + $cacheControlHeader = \Zend\Http\Header\CacheControl::fromString( 'Cache-Control: public, max-age=100, s-maxage=100' ); diff --git a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/PageCacheTest.php b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/PageCacheTest.php index 9b52a8ddc525c..6810d562389a2 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/PageCache/PageCacheTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/PageCache/PageCacheTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\App\Config\ScopePool::class, ['clean'], [], '', false); - $scopePool->expects($this->once())->method('clean'); - /** @var \Magento\Framework\App\ReinitableConfig $config */ - $config = $helper->getObject(\Magento\Framework\App\ReinitableConfig::class, ['scopePool' => $scopePool]); - $this->assertInstanceOf(\Magento\Framework\App\Config\ReinitableConfigInterface::class, $config->reinit()); - } -} diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php index 98742f397e1cf..a076e2e0ef3fc 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/Config/_files/valid_resources.xml b/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/Config/_files/valid_resources.xml index a42cfb478da8a..4bb71f77dc4e7 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/Config/_files/valid_resources.xml +++ b/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/Config/_files/valid_resources.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConfigTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConfigTest.php index 936a806432419..3042904fe22dc 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConfigTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConfigTest.php @@ -1,51 +1,64 @@ _scopeMock = $this->getMock(\Magento\Framework\Config\ScopeInterface::class); - $this->_cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); - - $this->_readerMock = - $this->getMock(\Magento\Framework\App\ResourceConnection\Config\Reader::class, [], [], '', false); + $this->scopeMock = $this->getMock(\Magento\Framework\Config\ScopeInterface::class); + $this->cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); + + $this->readerMock = $this->getMock( + \Magento\Framework\App\ResourceConnection\Config\Reader::class, + [], + [], + '', + false + ); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); - $this->_resourcesConfig = [ + $this->resourcesConfig = [ 'mainResourceName' => ['name' => 'mainResourceName', 'extends' => 'anotherResourceName'], 'otherResourceName' => ['name' => 'otherResourceName', 'connection' => 'otherConnectionName'], 'anotherResourceName' => ['name' => 'anotherResourceName', 'connection' => 'anotherConnection'], @@ -53,61 +66,61 @@ protected function setUp() 'extendedResourceName' => ['name' => 'extendedResourceName', 'extends' => 'validResource'], ]; - $this->_initialResources = [ - 'validResource' => ['connection' => 'validConnectionName'], - ]; - - $this->_cacheMock->expects( - $this->any() - )->method( - 'load' - )->will( - $this->returnValue(serialize($this->_resourcesConfig)) - ); - - $deploymentConfig = $this->getMock(\Magento\Framework\App\DeploymentConfig::class, [], [], '', false); - $deploymentConfig->expects($this->once()) - ->method('getConfigData') - ->with('resource') - ->willReturn($this->_initialResources); - - $this->_model = new \Magento\Framework\App\ResourceConnection\Config( - $this->_readerMock, - $this->_scopeMock, - $this->_cacheMock, - $deploymentConfig, - 'cacheId' + $serializedData = 'serialized data'; + $this->cacheMock->expects($this->any()) + ->method('load') + ->willReturn($serializedData); + $this->serializerMock->method('unserialize') + ->with($serializedData) + ->willReturn($this->resourcesConfig); + + $this->deploymentConfig = $this->getMock(\Magento\Framework\App\DeploymentConfig::class, [], [], '', false); + $this->config = new \Magento\Framework\App\ResourceConnection\Config( + $this->readerMock, + $this->scopeMock, + $this->cacheMock, + $this->deploymentConfig, + 'cacheId', + $this->serializerMock ); } /** - * @dataProvider getConnectionNameDataProvider * @param string $resourceName * @param string $connectionName + * @dataProvider getConnectionNameDataProvider */ public function testGetConnectionName($resourceName, $connectionName) { - $this->assertEquals($connectionName, $this->_model->getConnectionName($resourceName)); + $this->deploymentConfig->expects($this->once()) + ->method('getConfigData') + ->with(ConfigOptionsListConstants::KEY_RESOURCE) + ->willReturn([ + 'validResource' => ['connection' => 'validConnectionName'], + ]); + $this->assertEquals($connectionName, $this->config->getConnectionName($resourceName)); } /** * @expectedException \InvalidArgumentException */ - public function testExceptionConstructor() + public function testGetConnectionNameWithException() { - $deploymentConfig = $this->getMock(\Magento\Framework\App\DeploymentConfig::class, [], [], '', false); - $deploymentConfig->expects($this->once()) + $deploymentConfigMock = $this->getMock(\Magento\Framework\App\DeploymentConfig::class, [], [], '', false); + $deploymentConfigMock->expects($this->once()) ->method('getConfigData') - ->with('resource') + ->with(ConfigOptionsListConstants::KEY_RESOURCE) ->willReturn(['validResource' => ['somekey' => 'validConnectionName']]); - new \Magento\Framework\App\ResourceConnection\Config( - $this->_readerMock, - $this->_scopeMock, - $this->_cacheMock, - $deploymentConfig, - 'cacheId' + $config = new \Magento\Framework\App\ResourceConnection\Config( + $this->readerMock, + $this->scopeMock, + $this->cacheMock, + $deploymentConfigMock, + 'cacheId', + $this->serializerMock ); + $config->getConnectionName('default'); } /** diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConnectionFactoryTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConnectionFactoryTest.php index cab6d784275e9..a06be84a0b981 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConnectionFactoryTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/ResourceConnection/ConnectionFactoryTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Route/ConfigInterface/ProxyTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Route/ConfigInterface/ProxyTest.php index 6d65e95d847c1..f022a079e5c45 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Route/ConfigInterface/ProxyTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Route/ConfigInterface/ProxyTest.php @@ -1,6 +1,6 @@ _readerMock = $this->getMock(\Magento\Framework\App\Route\Config\Reader::class, [], [], '', false); $this->_cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); $this->_configScopeMock = $this->getMock(\Magento\Framework\Config\ScopeInterface::class); $this->_areaList = $this->getMock(\Magento\Framework\App\AreaList::class, [], [], '', false); - $this->_configScopeMock->expects( - $this->any() - )->method( - 'getCurrentScope' - )->will( - $this->returnValue('areaCode') - ); - $this->_config = new \Magento\Framework\App\Route\Config( - $this->_readerMock, - $this->_cacheMock, - $this->_configScopeMock, - $this->_areaList + $this->_configScopeMock->expects($this->any()) + ->method('getCurrentScope') + ->willReturn('areaCode'); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->_config = $objectManager->getObject( + \Magento\Framework\App\Route\Config::class, + [ + 'reader' => $this->_readerMock, + 'cache' => $this->_cacheMock, + 'configScope' => $this->_configScopeMock, + 'areaList' => $this->_areaList + ] ); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); + $objectManager->setBackwardCompatibleProperty($this->_config, 'serializer', $this->serializerMock); } public function testGetRouteFrontNameIfCacheIfRouterIdNotExist() { - $this->_cacheMock->expects( - $this->once() - )->method( - 'load' - )->with( - 'areaCode::RoutesConfig' - )->will( - $this->returnValue(serialize(['expected'])) - ); + $this->_cacheMock->expects($this->once()) + ->method('load') + ->with('areaCode::RoutesConfig') + ->willReturn('["expected"]'); $this->assertEquals('routerCode', $this->_config->getRouteFrontName('routerCode')); } public function testGetRouteByFrontName() { - $this->_cacheMock->expects( - $this->once() - )->method( - 'load' - )->with( - 'areaCode::RoutesConfig' - )->will( - $this->returnValue(serialize(['routerCode' => ['frontName' => 'routerName']])) - ); - - $this->assertEquals('routerCode', $this->_config->getRouteByFrontName('routerName')); - - // check internal caching in $this->_routes array + $data = ['routerCode' => ['frontName' => 'routerName']]; + $this->_cacheMock->expects($this->once()) + ->method('load') + ->with('areaCode::RoutesConfig') + ->willReturn('serializedData'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn($data); $this->assertEquals('routerCode', $this->_config->getRouteByFrontName('routerName')); } public function testGetRouteByFrontNameNoRoutes() { - $this->_cacheMock->expects( - $this->once() - )->method( - 'load' - )->with( - 'areaCode::RoutesConfig' - )->will( - $this->returnValue(serialize([])) - ); - - $this->assertFalse($this->_config->getRouteByFrontName('routerName')); - - // check caching in $this->_routes array + $this->_cacheMock->expects($this->once()) + ->method('load') + ->with('areaCode::RoutesConfig') + ->willReturn('serializedData'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn([]); $this->assertFalse($this->_config->getRouteByFrontName('routerName')); } public function testGetRouteByFrontNameNoCache() { - $this->_cacheMock->expects( - $this->once() - )->method( - 'load' - )->with( - 'scope::RoutesConfig' - )->will( - $this->returnValue(serialize(false)) - ); + $this->_cacheMock->expects($this->once()) + ->method('load') + ->with('scope::RoutesConfig') + ->willReturn('false'); $routes = [ 'routerCode' => [ @@ -127,6 +115,8 @@ public function testGetRouteByFrontNameNoCache() ], ]; + $serializedData = json_encode($routes); + $this->_readerMock->expects( $this->once() )->method( @@ -147,34 +137,29 @@ public function testGetRouteByFrontNameNoCache() $this->returnValue('default_router') ); - $this->_cacheMock->expects( - $this->once() - )->method( - 'save' - )->with( - serialize($routes), - 'scope::RoutesConfig' - ); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->willReturn($serializedData); - $this->assertEquals('routerCode', $this->_config->getRouteByFrontName('routerName', 'scope')); + $this->_cacheMock->expects($this->once()) + ->method('save') + ->with($serializedData, 'scope::RoutesConfig'); - // check caching in $this->_routes array $this->assertEquals('routerCode', $this->_config->getRouteByFrontName('routerName', 'scope')); } public function testGetModulesByFrontName() { - $this->_cacheMock->expects( - $this->once() - )->method( - 'load' - )->with( - 'areaCode::RoutesConfig' - )->will( - $this->returnValue( - serialize(['routerCode' => ['frontName' => 'routerName', 'modules' => ['Module1']]]) - ) - ); + $data = ['routerCode' => ['frontName' => 'routerName', 'modules' => ['Module1']]]; + + $this->_cacheMock->expects($this->once()) + ->method('load') + ->with('areaCode::RoutesConfig') + ->willReturn('serializedData'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with('serializedData') + ->willReturn($data); $this->assertEquals(['Module1'], $this->_config->getModulesByFrontName('routerName')); } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Router/ActionListTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Router/ActionListTest.php index c24c31e282c62..5be6bb0cb607e 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Router/ActionListTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Router/ActionListTest.php @@ -1,8 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->cacheMock = $this->getMockBuilder(\Magento\Framework\Config\CacheInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->moduleReaderMock = $this->getMockBuilder(\Magento\Framework\Module\Dir\Reader::class) - ->disableOriginalConstructor() - ->getMock(); + $this->cacheMock = $this->getMock( + \Magento\Framework\Config\CacheInterface::class, + [], + [], + '', + false + ); + $this->readerMock = $this->getMock( + \Magento\Framework\Module\Dir\Reader::class, + [], + [], + '', + false + ); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); } - public function testConstructorCachedData() + public function testConstructActionsCached() { $this->cacheMock->expects($this->once()) ->method('load') - ->will($this->returnValue(serialize('data'))); + ->willReturn('"data"'); + $this->serializerMock->expects($this->once()) + ->method('unserialize'); $this->cacheMock->expects($this->never()) ->method('save'); - $this->moduleReaderMock->expects($this->never()) + $this->readerMock->expects($this->never()) ->method('getActionFiles'); - $this->actionList = $this->objectManager->getObject( - \Magento\Framework\App\Router\ActionList::class, - [ - 'cache' => $this->cacheMock, - 'moduleReader' => $this->moduleReaderMock, - ] - ); + $this->createActionListInstance(); } - public function testConstructorNoCachedData() + public function testConstructActionsNoCached() { $this->cacheMock->expects($this->once()) ->method('load') - ->will($this->returnValue(false)); + ->willReturn(false); + $this->serializerMock->expects($this->once()) + ->method('serialize'); $this->cacheMock->expects($this->once()) ->method('save'); - $this->moduleReaderMock->expects($this->once()) + $this->readerMock->expects($this->once()) ->method('getActionFiles') - ->will($this->returnValue('data')); - $this->actionList = $this->objectManager->getObject( - \Magento\Framework\App\Router\ActionList::class, - [ - 'cache' => $this->cacheMock, - 'moduleReader' => $this->moduleReaderMock, - ] - ); + ->willReturn('data') + ; + $this->createActionListInstance(); } /** @@ -88,22 +93,15 @@ public function testConstructorNoCachedData() */ public function testGet($module, $area, $namespace, $action, $data, $expected) { - $this->cacheMock->expects($this->once()) ->method('load') ->will($this->returnValue(false)); $this->cacheMock->expects($this->once()) ->method('save'); - $this->moduleReaderMock->expects($this->once()) + $this->readerMock->expects($this->once()) ->method('getActionFiles') - ->will($this->returnValue($data)); - $this->actionList = $this->objectManager->getObject( - \Magento\Framework\App\Router\ActionList::class, - [ - 'cache' => $this->cacheMock, - 'moduleReader' => $this->moduleReaderMock, - ] - ); + ->willReturn($data); + $this->createActionListInstance(); $this->assertEquals($expected, $this->actionList->get($module, $area, $namespace, $action)); } @@ -168,4 +166,16 @@ public function getDataProvider() ], ]; } + + private function createActionListInstance() + { + $this->actionList = $this->objectManager->getObject( + \Magento\Framework\App\Router\ActionList::class, + [ + 'cache' => $this->cacheMock, + 'moduleReader' => $this->readerMock, + 'serializer' => $this->serializerMock, + ] + ); + } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Router/BaseTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Router/BaseTest.php index bf49959b67007..92561dbd37b17 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Router/BaseTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Router/BaseTest.php @@ -2,7 +2,7 @@ /** * Tests Magento\Framework\App\Router\Base * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Test\Unit\Router; @@ -80,7 +80,7 @@ public function testMatch() $moduleFrontName = 'module front name'; $actionPath = 'action path'; $actionName = 'action name'; - $actionClassName = \Magento\Cms\Controller\Index\Index::class; + $actionClassName = \Magento\Framework\App\Action\Action::class; $moduleName = 'module name'; $moduleList = [$moduleName]; @@ -109,7 +109,7 @@ public function testMatchUseParams() $moduleFrontName = 'module front name'; $actionPath = 'action path'; $actionName = 'action name'; - $actionClassName = \Magento\Cms\Controller\Index\Index::class; + $actionClassName = \Magento\Framework\App\Action\Action::class; $moduleName = 'module name'; $moduleList = [$moduleName]; $paramList = $moduleFrontName . '/' . $actionPath . '/' . $actionName . '/key/val/key2/val2/'; @@ -137,7 +137,7 @@ public function testMatchUseDefaultPath() $moduleFrontName = 'module front name'; $actionPath = 'action path'; $actionName = 'action name'; - $actionClassName = \Magento\Cms\Controller\Index\Index::class; + $actionClassName = \Magento\Framework\App\Action\Action::class; $moduleName = 'module name'; $moduleList = [$moduleName]; @@ -169,7 +169,7 @@ public function testMatchEmptyModuleList() $moduleFrontName = 'module front name'; $actionPath = 'action path'; $actionName = 'action name'; - $actionClassName = \Magento\Cms\Controller\Index\Index::class; + $actionClassName = \Magento\Framework\App\Action\Action::class; $emptyModuleList = []; // Stubs @@ -192,7 +192,7 @@ public function testMatchEmptyActionInstance() $moduleFrontName = 'module front name'; $actionPath = 'action path'; $actionName = 'action name'; - $actionClassName = \Magento\Cms\Controller\Index\Index::class; + $actionClassName = \Magento\Framework\App\Action\Action::class; $moduleName = 'module name'; $moduleList = [$moduleName]; diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Router/DefaultRouterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Router/DefaultRouterTest.php index fa25773fd0686..6df08386b9cb4 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Router/DefaultRouterTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Router/DefaultRouterTest.php @@ -2,7 +2,7 @@ /** * RouterList model test class * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\App\Test\Unit\Router; diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Router/NoRouteHandlerListTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Router/NoRouteHandlerListTest.php index 1af3a0b86ee7e..42623b4750377 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Router/NoRouteHandlerListTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Router/NoRouteHandlerListTest.php @@ -1,6 +1,6 @@ [ + [ + 'DOCUMENT_ROOT' => __DIR__ . '/_files/pub/', + 'SCRIPT_FILENAME' => __DIR__ . '/_files/pub/index.php', + ], + true + ], ]; } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ShellTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ShellTest.php index bb15ca757fc54..6695083308a7b 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ShellTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/ShellTest.php @@ -1,6 +1,6 @@ will( $this->returnValueMap( [ - [DirectoryList::GENERATION, DriverPool::FILE, $dir1], - [DirectoryList::DI, DriverPool::FILE, $dir2], + [DirectoryList::GENERATED_CODE, DriverPool::FILE, $dir1], + [DirectoryList::GENERATED_METADATA, DriverPool::FILE, $dir2], ] ) ); diff --git a/lib/internal/Magento/Framework/App/Test/Unit/StateTest.php b/lib/internal/Magento/Framework/App/Test/Unit/StateTest.php index c68d8eb30aed0..49f2c4febc3a9 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/StateTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/StateTest.php @@ -1,6 +1,6 @@ scopeMock = $this->getMockForAbstractClass( \Magento\Framework\Config\ScopeInterface::class, ['setCurrentScope'], '', false ); - $this->model = new \Magento\Framework\App\State($this->scopeMock); + + $this->areaListMock = $this->getMock(AreaList::class, [], [], '', false, false); + $this->areaListMock->expects($this->any()) + ->method('getCodes') + ->willReturn([Area::AREA_ADMINHTML, Area::AREA_FRONTEND]); + + $this->model = $objectManager->getObject( + \Magento\Framework\App\State::class, + ['configScope' => $this->scopeMock] + ); + + $objectManager->setBackwardCompatibleProperty($this->model, 'areaList', $this->areaListMock); } public function testSetAreaCode() { - $areaCode = 'some code'; + $areaCode = Area::AREA_FRONTEND; $this->scopeMock->expects($this->once())->method('setCurrentScope')->with($areaCode); $this->model->setAreaCode($areaCode); $this->setExpectedException(\Magento\Framework\Exception\LocalizedException::class); - $this->model->setAreaCode('any code'); + $this->model->setAreaCode(Area::AREA_ADMINHTML); } public function testGetAreaCodeException() @@ -49,7 +70,7 @@ public function testGetAreaCodeException() public function testGetAreaCode() { - $areaCode = 'some code'; + $areaCode = Area::AREA_FRONTEND; $this->scopeMock->expects($this->once())->method('setCurrentScope')->with($areaCode); $this->model->setAreaCode($areaCode); $this->assertEquals($areaCode, $this->model->getAreaCode()); @@ -57,8 +78,8 @@ public function testGetAreaCode() public function testEmulateAreaCode() { - $areaCode = 'original code'; - $emulatedCode = 'emulated code'; + $areaCode = Area::AREA_FRONTEND; + $emulatedCode = Area::AREA_ADMINHTML; $this->scopeMock->expects($this->once())->method('setCurrentScope')->with($areaCode); $this->model->setAreaCode($areaCode); $this->assertEquals( @@ -75,8 +96,8 @@ public function emulateAreaCodeCallback() public function testIsAreaCodeEmulated() { - $areaCode = 'original code'; - $emulatedCode = 'emulated code'; + $areaCode = Area::AREA_ADMINHTML; + $emulatedCode = Area::AREA_FRONTEND; $this->scopeMock->expects($this->once())->method('setCurrentScope')->with($areaCode); $this->model->setAreaCode($areaCode); $this->assertFalse( @@ -109,8 +130,8 @@ public function isAreaCodeEmulatedCallback() */ public function testEmulateAreaCodeException() { - $areaCode = 'original code'; - $emulatedCode = 'emulated code'; + $areaCode = Area::AREA_FRONTEND; + $emulatedCode = Area::AREA_ADMINHTML; $this->scopeMock->expects($this->once())->method('setCurrentScope')->with($areaCode); $this->model->setAreaCode($areaCode); $this->model->emulateAreaCode($emulatedCode, [$this, 'emulateAreaCodeCallbackException']); @@ -158,4 +179,13 @@ public function testConstructorException() "unknown mode" ); } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Area code "any code" does not exist + */ + public function testCheckAreaCodeException() + { + $this->model->setAreaCode('any code'); + } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php index 002e4746f6fb0..db50a8f2176dc 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php @@ -1,6 +1,6 @@ directory - ->expects($this->once()) - ->method('readFile') + $this->directory->expects($this->once()) + ->method('isReadable') ->with('fixture_file.txt') - ->will($this->returnValue('123')); - $this->assertEquals('123', $this->object->load()); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Exception to be propagated - */ - public function testLoadExceptionPropagation() - { - $this->directory - ->expects($this->once()) + ->willReturn(true); + $this->directory->expects($this->once()) ->method('readFile') ->with('fixture_file.txt') - ->will($this->throwException(new \Exception('Exception to be propagated'))); - $this->object->load(); - } - - /** - * @expectedException \UnexpectedValueException - * @expectedExceptionMessage Unable to retrieve deployment version of static files from the file system - */ - public function testLoadExceptionWrapping() - { - $filesystemException = new \Magento\Framework\Exception\FileSystemException( - new \Magento\Framework\Phrase('File does not exist') - ); - $this->directory - ->expects($this->once()) - ->method('readFile') - ->with('fixture_file.txt') - ->will($this->throwException($filesystemException)); - try { - $this->object->load(); - } catch (\Exception $e) { - $this->assertSame($filesystemException, $e->getPrevious(), 'Wrapping of original exception is expected'); - throw $e; - } + ->willReturn('123'); + $this->assertEquals('123', $this->object->load()); } public function testSave() diff --git a/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php b/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php index 30f398b4f6000..bbc56a95fe945 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/View/Deployment/VersionTest.php @@ -1,11 +1,11 @@ appState = $this->getMock(\Magento\Framework\App\State::class, [], [], '', false); - $this->versionStorage = $this->getMock(\Magento\Framework\App\View\Deployment\Version\StorageInterface::class); - $this->object = new Version($this->appState, $this->versionStorage); - } - - public function testGetValueDeveloperMode() - { - $this->appState - ->expects($this->once()) - ->method('getMode') - ->will($this->returnValue(\Magento\Framework\App\State::MODE_DEVELOPER)); - $this->versionStorage->expects($this->never())->method($this->anything()); - $this->assertInternalType('integer', $this->object->getValue()); - $this->object->getValue(); // Ensure computation occurs only once and result is cached in memory + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->appStateMock = $this->getMock(\Magento\Framework\App\State::class, [], [], '', false); + $this->versionStorageMock = $this->getMock( + \Magento\Framework\App\View\Deployment\Version\StorageInterface::class + ); + $this->loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class); + $this->object = new Version($this->appStateMock, $this->versionStorageMock); + $objectManager->setBackwardCompatibleProperty($this->object, 'logger', $this->loggerMock); } /** @@ -51,12 +50,12 @@ public function testGetValueDeveloperMode() */ public function testGetValueFromStorage($appMode) { - $this->appState + $this->appStateMock ->expects($this->once()) ->method('getMode') ->will($this->returnValue($appMode)); - $this->versionStorage->expects($this->once())->method('load')->will($this->returnValue('123')); - $this->versionStorage->expects($this->never())->method('save'); + $this->versionStorageMock->expects($this->once())->method('load')->will($this->returnValue('123')); + $this->versionStorageMock->expects($this->never())->method('save'); $this->assertEquals('123', $this->object->getValue()); $this->object->getValue(); // Ensure caching in memory } @@ -70,20 +69,46 @@ public function getValueFromStorageDataProvider() ]; } - public function testGetValueDefaultModeSaving() + public function testGetValueInNonProductionMode() { - $versionType = 'integer'; - $this->appState - ->expects($this->once()) + $version = 123123123123; + $this->versionStorageMock->expects($this->once()) + ->method('load') + ->willReturn($version); + + $this->assertEquals($version, $this->object->getValue()); + $this->object->getValue(); + } + + /** + * @expectedException \UnexpectedValueException + */ + public function testGetValueWithProductionModeAndException() + { + $this->versionStorageMock->expects($this->once()) + ->method('load') + ->willReturn(false); + $this->appStateMock->expects($this->once()) ->method('getMode') - ->will($this->returnValue(\Magento\Framework\App\State::MODE_DEFAULT)); - $storageException = new \UnexpectedValueException('Does not exist in the storage'); - $this->versionStorage - ->expects($this->once()) + ->willReturn(\Magento\Framework\App\State::MODE_PRODUCTION); + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with('Can not load static content version.'); + + $this->object->getValue(); + } + + public function testGetValueWithProductionMode() + { + $this->versionStorageMock->expects($this->once()) ->method('load') - ->will($this->throwException($storageException)); - $this->versionStorage->expects($this->once())->method('save')->with($this->isType($versionType)); - $this->assertInternalType($versionType, $this->object->getValue()); - $this->object->getValue(); // Ensure caching in memory + ->willReturn(false); + $this->appStateMock->expects($this->once()) + ->method('getMode') + ->willReturn(\Magento\Framework\App\State::MODE_DEFAULT); + $this->versionStorageMock->expects($this->once()) + ->method('save'); + + $this->assertNotNull($this->object->getValue()); } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ViewTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ViewTest.php index e03b86ffd1001..bf1f2a3563d44 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ViewTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/ViewTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/_files/config.php b/lib/internal/Magento/Framework/App/Test/Unit/_files/config.php index 9a10809b20f35..69f881a7919b4 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/_files/config.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/_files/config.php @@ -1,6 +1,6 @@ versionStorage->load(); - } catch (\UnexpectedValueException $e) { - $result = (new \DateTime())->getTimestamp(); - $this->versionStorage->save($result); - } - break; + $result = $this->versionStorage->load(); + if (!$result) { + if ($appMode == \Magento\Framework\App\State::MODE_PRODUCTION) { + $this->getLogger()->critical('Can not load static content version.'); + throw new \UnexpectedValueException( + "Unable to retrieve deployment version of static files from the file system." + ); + } + $result = $this->generateVersion(); + $this->versionStorage->save($result); + } + return $result; + } - case \Magento\Framework\App\State::MODE_DEVELOPER: - $result = (new \DateTime())->getTimestamp(); - break; + /** + * Generate version of static content + * + * @return int + */ + private function generateVersion() + { + return time(); + } - default: - $result = $this->versionStorage->load(); + /** + * Get logger + * + * @return LoggerInterface + * @deprecated + */ + private function getLogger() + { + if ($this->logger == null) { + $this->logger = \Magento\Framework\App\ObjectManager::getInstance() + ->get(LoggerInterface::class); } - return $result; + return $this->logger; } } diff --git a/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php b/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php index 4f8813df774d7..5233208cfd74d 100644 --- a/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php +++ b/lib/internal/Magento/Framework/App/View/Deployment/Version/Storage/File.php @@ -1,6 +1,6 @@ directory->isReadable($this->fileName)) { return $this->directory->readFile($this->fileName); - } catch (\Magento\Framework\Exception\FileSystemException $e) { - throw new \UnexpectedValueException( - 'Unable to retrieve deployment version of static files from the file system.', - 0, - $e - ); } + return false; } /** diff --git a/lib/internal/Magento/Framework/App/View/Deployment/Version/StorageInterface.php b/lib/internal/Magento/Framework/App/View/Deployment/Version/StorageInterface.php index e56e331f1b32a..6dfbca7fd2eff 100644 --- a/lib/internal/Magento/Framework/App/View/Deployment/Version/StorageInterface.php +++ b/lib/internal/Magento/Framework/App/View/Deployment/Version/StorageInterface.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/App/etc/routes.xsd b/lib/internal/Magento/Framework/App/etc/routes.xsd index 0edea0731dc44..b4e0063b38b16 100644 --- a/lib/internal/Magento/Framework/App/etc/routes.xsd +++ b/lib/internal/Magento/Framework/App/etc/routes.xsd @@ -3,7 +3,7 @@ /** * This schema should be applied for validation of separate router.xml files * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/lib/internal/Magento/Framework/App/etc/routes_merged.xsd b/lib/internal/Magento/Framework/App/etc/routes_merged.xsd index 972b8fb348922..a5b3efca864a5 100644 --- a/lib/internal/Magento/Framework/App/etc/routes_merged.xsd +++ b/lib/internal/Magento/Framework/App/etc/routes_merged.xsd @@ -3,7 +3,7 @@ /** * This schema should be applied for validation of merged router.xml file * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/lib/internal/Magento/Framework/AppInterface.php b/lib/internal/Magento/Framework/AppInterface.php index d9a532b540142..31fc7d0fedd82 100644 --- a/lib/internal/Magento/Framework/AppInterface.php +++ b/lib/internal/Magento/Framework/AppInterface.php @@ -2,7 +2,7 @@ /** * Application interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework; diff --git a/lib/internal/Magento/Framework/Archive.php b/lib/internal/Magento/Framework/Archive.php index e8c69928aba04..b6f30b5d95af1 100644 --- a/lib/internal/Magento/Framework/Archive.php +++ b/lib/internal/Magento/Framework/Archive.php @@ -1,6 +1,6 @@ getPath(DirectoryList::GENERATION); + $generationDir = $dirList->getPath(DirectoryList::GENERATED_CODE); $frameworkDir = $dirList->getPath(DirectoryList::LIB_INTERNAL); $autoloader->addPsr4('Magento\\', [$generationDir . '/Magento/'], true); diff --git a/lib/internal/Magento/Framework/Autoload/Test/Unit/ClassLoaderWrapperTest.php b/lib/internal/Magento/Framework/Autoload/Test/Unit/ClassLoaderWrapperTest.php index be40adcdc0edc..9181b82197183 100644 --- a/lib/internal/Magento/Framework/Autoload/Test/Unit/ClassLoaderWrapperTest.php +++ b/lib/internal/Magento/Framework/Autoload/Test/Unit/ClassLoaderWrapperTest.php @@ -1,6 +1,6 @@ method('addPsr4') ->with( 'Magento\\', - [DirectoryList::GENERATION . '/Magento/'], + [DirectoryList::GENERATED_CODE . '/Magento/'], true ); $mockAutoloader->expects($this->at(1)) @@ -46,7 +46,7 @@ public function testPopulateMappings() ->with('Credis_', DirectoryList::LIB_INTERNAL, true); $mockAutoloader->expects($this->at(3)) ->method('addPsr0') - ->with('', [DirectoryList::GENERATION]); + ->with('', [DirectoryList::GENERATED_CODE]); Populator::populateMappings($mockAutoloader, $this->mockDirectoryList); } diff --git a/lib/internal/Magento/Framework/Backup/AbstractBackup.php b/lib/internal/Magento/Framework/Backup/AbstractBackup.php index 9d242fdc5e71d..4afd555d96858 100644 --- a/lib/internal/Magento/Framework/Backup/AbstractBackup.php +++ b/lib/internal/Magento/Framework/Backup/AbstractBackup.php @@ -1,6 +1,6 @@ rollBackFtp) { $this->rollBackFtp = ObjectManager::getInstance()->create( \Magento\Framework\Backup\Filesystem\Rollback\Ftp::class, - [$this] + ['snapshotObject' => $this] ); } @@ -332,7 +332,7 @@ protected function getRollBackFs() if (!$this->rollBackFs) { $this->rollBackFs = ObjectManager::getInstance()->create( \Magento\Framework\Backup\Filesystem\Rollback\Fs::class, - [$this] + ['snapshotObject' => $this] ); } diff --git a/lib/internal/Magento/Framework/Backup/Filesystem/Helper.php b/lib/internal/Magento/Framework/Backup/Filesystem/Helper.php index 2587cd543818a..7e2fadab1b874 100644 --- a/lib/internal/Magento/Framework/Backup/Filesystem/Helper.php +++ b/lib/internal/Magento/Framework/Backup/Filesystem/Helper.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Cache/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/Cache/Test/Unit/ConfigTest.php index a4e1a248a51d9..212c151c25955 100644 --- a/lib/internal/Magento/Framework/Cache/Test/Unit/ConfigTest.php +++ b/lib/internal/Magento/Framework/Cache/Test/Unit/ConfigTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Code/GeneratedFiles.php b/lib/internal/Magento/Framework/Code/GeneratedFiles.php index 75d5ff4b4b73b..4ee3c6680d6dd 100644 --- a/lib/internal/Magento/Framework/Code/GeneratedFiles.php +++ b/lib/internal/Magento/Framework/Code/GeneratedFiles.php @@ -1,6 +1,6 @@ write->getRelativePath($this->directoryList->getPath(DirectoryList::CACHE)); - $generationPath = $this->write->getRelativePath($this->directoryList->getPath(DirectoryList::GENERATION)); - $diPath = $this->write->getRelativePath($this->directoryList->getPath(DirectoryList::DI)); + $generationPath = $this->write->getRelativePath( + $this->directoryList->getPath(DirectoryList::GENERATED_CODE) + ); + $diPath = $this->write->getRelativePath($this->directoryList->getPath(DirectoryList::GENERATED_METADATA)); - // Clean var/generation dir + // Clean generated/code dir if ($this->write->isDirectory($generationPath)) { $this->write->delete($generationPath); } - // Clean var/di + // Clean generated/metadata if ($this->write->isDirectory($diPath)) { $this->write->delete($diPath); } @@ -101,7 +103,7 @@ public function cleanGeneratedFiles() } /** - * Create flag for cleaning up var/generation, var/di and var/cache directories for subsequent + * Create flag for cleaning up generated/code, generated/metadata and var/cache directories for subsequent * regeneration of this content * * @return void @@ -133,7 +135,6 @@ private function getEnabledCacheTypes() return $enabledCacheTypes; } - /** * Returns path to env.php file * @@ -183,8 +184,7 @@ private function disableAllCacheTypes() * Enables apppropriate cache types in app/etc/env.php based on the passed in $cacheTypes array * TODO: to be removed in scope of MAGETWO-53476 * - * @param string[] - * + * @param string[] $cacheTypes * @return void */ private function enableCacheTypes($cacheTypes) diff --git a/lib/internal/Magento/Framework/Code/Generator.php b/lib/internal/Magento/Framework/Code/Generator.php index 40f9ac671d765..02cb70b15004f 100644 --- a/lib/internal/Magento/Framework/Code/Generator.php +++ b/lib/internal/Magento/Framework/Code/Generator.php @@ -1,6 +1,6 @@ getFileName() || false == $class->hasMethod( + if ($class->isInterface() || !$class->getFileName() || false == $class->hasMethod( '__construct' ) || !$inherited && $class->getConstructor()->class != $class->getName() ) { diff --git a/lib/internal/Magento/Framework/Code/Reader/ClassReader.php b/lib/internal/Magento/Framework/Code/Reader/ClassReader.php index 50783796288d9..37029255b0f20 100644 --- a/lib/internal/Magento/Framework/Code/Reader/ClassReader.php +++ b/lib/internal/Magento/Framework/Code/Reader/ClassReader.php @@ -1,6 +1,6 @@ $methodMetadata[Config::SCHEMA_METHOD_HANDLER]] ]; } + + /** + * Generate topic name based on service type and method name. + * + * Perform the following conversion: + * \Magento\Customer\Api\RepositoryInterface + getById => magento.customer.api.repositoryInterface.getById + * + * @param string $typeName + * @param string $methodName + * @return string + */ + public function generateTopicName($typeName, $methodName) + { + $parts = explode('\\', ltrim($typeName, '\\')); + foreach ($parts as &$part) { + $part = lcfirst($part); + } + return implode('.', $parts) . '.' . $methodName; + } } diff --git a/lib/internal/Magento/Framework/Communication/Config/Validator.php b/lib/internal/Magento/Framework/Communication/Config/Validator.php index 6be205d3192b7..42d30e50ea6db 100644 --- a/lib/internal/Magento/Framework/Communication/Config/Validator.php +++ b/lib/internal/Magento/Framework/Communication/Config/Validator.php @@ -1,6 +1,6 @@ @@ -54,7 +54,7 @@ - + @@ -65,7 +65,7 @@ - + @@ -76,7 +76,7 @@ - + diff --git a/lib/internal/Magento/Framework/Component/ComponentFile.php b/lib/internal/Magento/Framework/Component/ComponentFile.php index f5f325ac5b36a..df80eed3ab15e 100644 --- a/lib/internal/Magento/Framework/Component/ComponentFile.php +++ b/lib/internal/Magento/Framework/Component/ComponentFile.php @@ -1,6 +1,6 @@ runComposerCommand( [ 'command' => 'remove', - 'packages' => $packages + 'packages' => $packages, + '--no-update' => true, ] ); } diff --git a/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerFactoryTest.php b/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerFactoryTest.php index 3f4361eefa3b3..31e62d0b2b06e 100644 --- a/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerFactoryTest.php +++ b/lib/internal/Magento/Framework/Composer/Test/Unit/ComposerFactoryTest.php @@ -1,6 +1,6 @@ reader = $reader; $this->cache = $cache; $this->cacheId = $cacheId; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); $this->initData(); } /** * Initialise data for configuration + * * @return void */ protected function initData() @@ -89,10 +101,11 @@ protected function initData() $data = $this->cache->load($this->cacheId); if (false === $data) { $data = $this->reader->read(); - $this->cache->save(serialize($data), $this->cacheId, $this->cacheTags); + $this->cache->save($this->serializer->serialize($data), $this->cacheId, $this->cacheTags); } else { - $data = unserialize($data); + $data = $this->serializer->unserialize($data); } + $this->merge($data); } @@ -133,6 +146,7 @@ public function get($path = null, $default = null) /** * Clear cache data + * * @return void */ public function reset() diff --git a/lib/internal/Magento/Framework/Config/Data/ConfigData.php b/lib/internal/Magento/Framework/Config/Data/ConfigData.php index 5e36583f51af2..e86668ec809a1 100644 --- a/lib/internal/Magento/Framework/Config/Data/ConfigData.php +++ b/lib/internal/Magento/Framework/Config/Data/ConfigData.php @@ -1,6 +1,6 @@ _reader = $reader; $this->_configScope = $configScope; $this->_cache = $cache; $this->_cacheId = $cacheId; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); } /** @@ -98,11 +112,14 @@ protected function _loadScopedData() if (false == isset($this->_loadedScopes[$scopeCode])) { if ($scopeCode !== 'primary' && ($data = $this->_cache->load($scopeCode . '::' . $this->_cacheId)) ) { - $data = unserialize($data); + $data = $this->serializer->unserialize($data); } else { $data = $this->_reader->read($scopeCode); if ($scopeCode !== 'primary') { - $this->_cache->save(serialize($data), $scopeCode . '::' . $this->_cacheId); + $this->_cache->save( + $this->serializer->serialize($data), + $scopeCode . '::' . $this->_cacheId + ); } } $this->merge($data); diff --git a/lib/internal/Magento/Framework/Config/DataInterface.php b/lib/internal/Magento/Framework/Config/DataInterface.php index 91ba5d79e1dcc..391004f84812e 100644 --- a/lib/internal/Magento/Framework/Config/DataInterface.php +++ b/lib/internal/Magento/Framework/Config/DataInterface.php @@ -1,6 +1,6 @@ 'env.php', ]; + /** + * Initial files for configuration + * + * @var array + */ + private $initialConfigFiles = [ + self::DIST => [ + self::APP_CONFIG => 'config.dist.php', + self::APP_ENV => 'env.dist.php', + ], + self::LOCAL => [ + self::APP_CONFIG => 'config.local.php', + self::APP_ENV => 'env.local.php', + ] + ]; + /** * Constructor * @@ -35,7 +54,7 @@ public function __construct($additionalConfigFiles = []) } /** - * Returns application config files + * Returns application config files. * * @return array */ @@ -58,4 +77,25 @@ public function getPath($fileKey) } return $this->applicationConfigFiles[$fileKey]; } + + /** + * Returns application initial config files. + * + * @return array + */ + public function getInitialFilePools() + { + return $this->initialConfigFiles; + } + + /** + * Retrieve all config file pools. + * + * @param string $pool + * @return array + */ + public function getPathsByPool($pool) + { + return $this->initialConfigFiles[$pool]; + } } diff --git a/lib/internal/Magento/Framework/Config/FileIterator.php b/lib/internal/Magento/Framework/Config/FileIterator.php index 84ea786c8ae6c..5eee156864198 100644 --- a/lib/internal/Magento/Framework/Config/FileIterator.php +++ b/lib/internal/Magento/Framework/Config/FileIterator.php @@ -1,7 +1,7 @@ sources = $this->prepareSources($sources); + } + + /** + * Read configuration data + * + * @param null|string $scope + * @throws LocalizedException Exception is thrown when scope other than default is given + * @return array + */ + public function read($scope = null) + { + $config = []; + foreach ($this->sources as $sourceData) { + /** @var \Magento\Framework\App\Config\Reader\Source\SourceInterface $source */ + $source = $sourceData['class']; + $config = array_replace_recursive($config, $source->get($scope)); + } + + return $config; + } + + /** + * Prepare source for usage + * + * @param array $array + * @return array + */ + private function prepareSources(array $array) + { + $array = array_filter( + $array, + function ($item) { + return (!isset($item['disable']) || !$item['disable']) && $item['class']; + } + ); + uasort( + $array, + function ($firstItem, $nexItem) { + if ((int)$firstItem['sortOrder'] == (int)$nexItem['sortOrder']) { + return 0; + } + return (int)$firstItem['sortOrder'] < (int)$nexItem['sortOrder'] ? -1 : 1; + } + ); + + return $array; + } +} diff --git a/lib/internal/Magento/Framework/Config/Reader/Filesystem.php b/lib/internal/Magento/Framework/Config/Reader/Filesystem.php index eb456f787cd8e..902ae7ffb95cd 100644 --- a/lib/internal/Magento/Framework/Config/Reader/Filesystem.php +++ b/lib/internal/Magento/Framework/Config/Reader/Filesystem.php @@ -2,7 +2,7 @@ /** * Filesystem configuration loader. Loads configuration from XML files, split by scopes * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. * */ diff --git a/lib/internal/Magento/Framework/Config/ReaderInterface.php b/lib/internal/Magento/Framework/Config/ReaderInterface.php index b6e1667d8ae6b..25c6a625e4826 100644 --- a/lib/internal/Magento/Framework/Config/ReaderInterface.php +++ b/lib/internal/Magento/Framework/Config/ReaderInterface.php @@ -2,7 +2,7 @@ /** * Reader responsible for retrieving provided scope of configuration from storage * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Config; diff --git a/lib/internal/Magento/Framework/Config/SchemaLocator.php b/lib/internal/Magento/Framework/Config/SchemaLocator.php index ba211f8bbdef7..b63c249c63cb2 100644 --- a/lib/internal/Magento/Framework/Config/SchemaLocator.php +++ b/lib/internal/Magento/Framework/Config/SchemaLocator.php @@ -2,7 +2,7 @@ /** * Menu configuration schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Config; diff --git a/lib/internal/Magento/Framework/Config/SchemaLocatorInterface.php b/lib/internal/Magento/Framework/Config/SchemaLocatorInterface.php index c6efde8599439..450465c02e8b4 100644 --- a/lib/internal/Magento/Framework/Config/SchemaLocatorInterface.php +++ b/lib/internal/Magento/Framework/Config/SchemaLocatorInterface.php @@ -2,7 +2,7 @@ /** * Configuration validation schema locator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Config; diff --git a/lib/internal/Magento/Framework/Config/Scope.php b/lib/internal/Magento/Framework/Config/Scope.php index 44c7a736fbcd4..55bca0f2a4771 100644 --- a/lib/internal/Magento/Framework/Config/Scope.php +++ b/lib/internal/Magento/Framework/Config/Scope.php @@ -1,6 +1,6 @@ objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->_readerMock = $this->getMock(\Magento\Framework\Config\ReaderInterface::class); $this->_configScopeMock = $this->getMock(\Magento\Framework\Config\ScopeInterface::class); $this->_cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); - $this->_model = new \Magento\Framework\Config\Data\Scoped( - $this->_readerMock, - $this->_configScopeMock, - $this->_cacheMock, - 'tag' + $this->_model = $this->objectManager->getObject( + \Magento\Framework\Config\Data\Scoped::class, + [ + 'reader' => $this->_readerMock, + 'configScope' => $this->_configScopeMock, + 'cache' => $this->_cacheMock, + 'cacheId' => 'tag', + 'serializer' => $this->serializerMock + ] ); } @@ -47,7 +63,7 @@ protected function setUp() * @param string $default * @dataProvider getConfigByPathDataProvider */ - public function testgetConfigByPath($path, $expectedValue, $default) + public function testGetConfigByPath($path, $expectedValue, $default) { $testData = [ 'key_1' => [ @@ -55,7 +71,12 @@ public function testgetConfigByPath($path, $expectedValue, $default) 'key_1.2' => ['some' => 'arrayValue'], ], ]; - $this->_cacheMock->expects($this->any())->method('load')->will($this->returnValue(serialize([]))); + $this->_cacheMock->expects($this->once()) + ->method('load') + ->willReturn(false); + $this->_readerMock->expects($this->once()) + ->method('read') + ->willReturn([]); $this->_model->merge($testData); $this->assertEquals($expectedValue, $this->_model->get($path, $default)); } @@ -77,6 +98,7 @@ public function getConfigByPathDataProvider() public function testGetScopeSwitchingWithNonCachedData() { $testValue = ['some' => 'testValue']; + $serializedData = 'serialized data'; /** change current area */ $this->_configScopeMock->expects( @@ -109,8 +131,15 @@ public function testGetScopeSwitchingWithNonCachedData() $this->returnValue($testValue) ); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($testValue) + ->willReturn($serializedData); + /** test cache saving */ - $this->_cacheMock->expects($this->once())->method('save')->with(serialize($testValue), 'adminhtml::tag'); + $this->_cacheMock->expects($this->once()) + ->method('save') + ->with($serializedData, 'adminhtml::tag'); /** test config value existence */ $this->assertEquals('testValue', $this->_model->get('some')); @@ -122,6 +151,7 @@ public function testGetScopeSwitchingWithNonCachedData() public function testGetScopeSwitchingWithCachedData() { $testValue = ['some' => 'testValue']; + $serializedData = 'serialized data'; /** change current area */ $this->_configScopeMock->expects( @@ -132,16 +162,16 @@ public function testGetScopeSwitchingWithCachedData() $this->returnValue('adminhtml') ); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($serializedData) + ->willReturn($testValue); + /** set cache data */ - $this->_cacheMock->expects( - $this->once() - )->method( - 'load' - )->with( - 'adminhtml::tag' - )->will( - $this->returnValue(serialize($testValue)) - ); + $this->_cacheMock->expects($this->once()) + ->method('load') + ->with('adminhtml::tag') + ->willReturn($serializedData); /** test preventing of getting data from reader */ $this->_readerMock->expects($this->never())->method('read'); diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/DataTest.php b/lib/internal/Magento/Framework/Config/Test/Unit/DataTest.php index 5c58310e096bb..cec1c3b0c8099 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/DataTest.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/DataTest.php @@ -1,6 +1,6 @@ reader = $this->getMockBuilder(\Magento\Framework\Config\ReaderInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->cache = $this->getMockBuilder(\Magento\Framework\Config\CacheInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->readerMock = $this->getMock(\Magento\Framework\Config\ReaderInterface::class); + $this->cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); } - public function testGet() + public function testGetConfigNotCached() { $data = ['a' => 'b']; - $cacheid = 'test'; - $this->cache->expects($this->once())->method('load')->will($this->returnValue(false)); - $this->reader->expects($this->once())->method('read')->will($this->returnValue($data)); - + $cacheId = 'test'; + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn(false); + $this->readerMock->expects($this->once()) + ->method('read') + ->willReturn($data); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($data); $config = new \Magento\Framework\Config\Data( - $this->reader, $this->cache, $cacheid + $this->readerMock, + $this->cacheMock, + $cacheId, + $this->serializerMock ); $this->assertEquals($data, $config->get()); $this->assertEquals('b', $config->get('a')); @@ -44,18 +57,50 @@ public function testGet() $this->assertEquals(33, $config->get('a/b', 33)); } - public function testReset() + public function testGetConfigCached() { - $cacheid = 'test'; - $this->cache->expects($this->once())->method('load')->will($this->returnValue(serialize([]))); - $this->cache->expects($this->once())->method('remove')->with($cacheid); - + $data = ['a' => 'b']; + $serializedData = '{"a":"b"}'; + $cacheId = 'test'; + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn($serializedData); + $this->readerMock->expects($this->never()) + ->method('read'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($serializedData) + ->willReturn($data); $config = new \Magento\Framework\Config\Data( - $this->reader, - $this->cache, - $cacheid + $this->readerMock, + $this->cacheMock, + $cacheId, + $this->serializerMock ); + $this->assertEquals($data, $config->get()); + $this->assertEquals('b', $config->get('a')); + } + public function testReset() + { + $serializedData = ''; + $cacheId = 'test'; + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn($serializedData); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($serializedData) + ->willReturn([]); + $this->cacheMock->expects($this->once()) + ->method('remove') + ->with($cacheId); + $config = new \Magento\Framework\Config\Data( + $this->readerMock, + $this->cacheMock, + $cacheId, + $this->serializerMock + ); $config->reset(); } } diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/Dom/ArrayNodeConfigTest.php b/lib/internal/Magento/Framework/Config/Test/Unit/Dom/ArrayNodeConfigTest.php index afe17fa67d4f1..97ef73dcf2adc 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/Dom/ArrayNodeConfigTest.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/Dom/ArrayNodeConfigTest.php @@ -1,6 +1,6 @@ source = $this->getMockBuilder(SourceInterface::class) + ->getMockForAbstractClass(); + $this->reader = new Reader([['class' => $this->source]]); + } + + public function testRead() + { + $config = [ + 'default' => [ + 'general/locale/code'=> 'ru_RU', + 'general/locale/timezone'=> 'America/Chicago', + ] + ]; + $this->source->expects($this->once()) + ->method('get') + ->with(null) + ->willReturn($config); + $this->assertEquals($config, $this->reader->read()); + } +} diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/ScopeTest.php b/lib/internal/Magento/Framework/Config/Test/Unit/ScopeTest.php index 257d95d8c37e8..1b90507d5639c 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/ScopeTest.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/ScopeTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test/theme.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test/theme.xml index 36a606ac057f9..9173b0981ec2d 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test/theme.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test/theme.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test2/theme.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test2/theme.xml index 34aaacbfd6347..6e6062b45ba1a 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test2/theme.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/default_test2/theme.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_default/theme.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_default/theme.xml index 937c33ce4662d..24d4d5b46b3d7 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_default/theme.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_default/theme.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_external_package_descendant/theme.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_external_package_descendant/theme.xml index 9dbbd03eb6e0d..e0c09036aa113 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_external_package_descendant/theme.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/area/test_external_package_descendant/theme.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/attributes.php b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/attributes.php index 979bb9f6d1168..695bb1e66f16c 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/attributes.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/attributes.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/cdata.php b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/cdata.php index 5f018f418b333..73b5e98545794 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/cdata.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/cdata.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/result.php b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/result.php index 1ecf62df9813a..01701bc0ccbe4 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/result.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/result.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_notuniq.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_notuniq.xml index 2fd96b65ed32b..a8e8ef10e9a1f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_notuniq.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_notuniq.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_wrongarray.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_wrongarray.xml index 433e6ab9040f3..a0844e6309d0c 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_wrongarray.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/converter/dom/flat/source_wrongarray.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_merged.xml index 77a770181154a..808949ac34e40 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_one.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_one.xml index 77a770181154a..808949ac34e40 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_one.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_one.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_two.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_two.xml index 11e0e9ad346e8..04d7ce5767db5 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_two.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_new_two.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_one.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_one.xml index 22e79d8a382ba..634ff9a44588f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_one.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_one.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_two.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_two.xml index 8f76f92eb4641..fd1f5fc61d545 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_two.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ambiguous_two.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes.xml index 8d2b1136b4e28..e7328d629c321 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_merged.xml index 2ee72eb3c497d..9c9962da64665 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_new.xml index 89ff68df93817..298ee2ba22f15 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/attributes_new.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/cdata.php b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/cdata.php index c691465160c07..5a8f0198dbcb0 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/cdata.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/cdata.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/no_attributes.php b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/no_attributes.php index e71787e7ecdd8..9b50697651e7b 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/no_attributes.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/no_attributes.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/with_attributes.php b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/with_attributes.php index 67e1d32fddc82..54aa19ca64425 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/with_attributes.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/converter/with_attributes.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids.xml index 1b122d7e4d945..3cd91e441d850 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_merged.xml index 3eb3d825193f3..ea045ed4c4c6a 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_new.xml index a56666c7a9201..30dcd761a8423 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/ids_new.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced.xml index d7814a418574f..b996ce6c4717c 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_merged.xml index bdc62a58f53e3..7badd80b73b6f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_new.xml index fa18cb430c243..ddd1f97cdf9b1 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/namespaced_new.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids.xml index 371fed257d238..31604e890a682 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_merged.xml index 79b8a3c1a066a..b3b3092330c25 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_new.xml index d0b483435ae76..0747eb5b470fd 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/no_ids_new.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node.xml index 4a8320c0c49f2..e11388f3d5ee0 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_merged.xml index 4a8320c0c49f2..e11388f3d5ee0 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_merged.xml @@ -1,7 +1,7 @@ @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_new.xml index 7c7b9cb155879..b6a04c46ddd46 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/override_node_new.xml @@ -1,7 +1,7 @@ @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive.xml index 976acad4e5680..05fd81f2a9299 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep.xml index 1eafa6a3c71bf..3aa5b7e9e54ab 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_merged.xml index 941de2ddcd5ef..e326a81f33e29 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_new.xml index 46c6a895cd15e..1afb4db78167f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_deep_new.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_merged.xml index 693d7d684fdd6..4dc5163e6461f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_new.xml index a309e7ab14b15..6b7aaa63902a8 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/recursive_new.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node.xml index 6f45ac413b32b..d880659788c1e 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node.xml @@ -1,7 +1,7 @@ @@ -9,4 +9,4 @@ Some Phrase - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_merged.xml index 9b255a09ecea5..4826bab100f5f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_merged.xml @@ -1,7 +1,7 @@ @@ -9,4 +9,4 @@ Some Other Phrase - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_new.xml index 9b255a09ecea5..4826bab100f5f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/text_node_new.xml @@ -1,7 +1,7 @@ @@ -9,4 +9,4 @@ Some Other Phrase - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types.xml index ea8833a096472..79b2ed02d3045 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_merged.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_merged.xml index 78e8bba8427f2..91bbb1243ae1f 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_merged.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_merged.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_new.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_new.xml index c79575ea5e641..5a4bb9ecda6b6 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_new.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/dom/types_new.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/config.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/config.xml index 93ec5f0fcce89..82b6fdbef6432 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/config.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/config.xml @@ -1,7 +1,7 @@ @@ -12,4 +12,4 @@ -
    \ No newline at end of file +
    diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/schema.xsd b/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/schema.xsd index 62a9fdc20aa90..e60063522c757 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/schema.xsd +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/reader/schema.xsd @@ -1,10 +1,10 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/sample.xsd b/lib/internal/Magento/Framework/Config/Test/Unit/_files/sample.xsd index dd0a6590e883c..21c672f552283 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/sample.xsd +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/sample.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/theme_invalid.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/theme_invalid.xml index 3dd3a0cfd6455..0b2f14bea7d94 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/theme_invalid.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/theme_invalid.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_invalid.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_invalid.xml index 946901dfa646d..4b31a0aee8c22 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_invalid.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_invalid.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_one.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_one.xml index 3291a94d11bb2..dec0e4fda45db 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_one.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_one.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_two.xml b/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_two.xml index 8747cb214a4a6..5fff96a18f2c9 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_two.xml +++ b/lib/internal/Magento/Framework/Config/Test/Unit/_files/view_two.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Config/Theme.php b/lib/internal/Magento/Framework/Config/Theme.php index d06f4f6da7af7..1ab2271735e42 100644 --- a/lib/internal/Magento/Framework/Config/Theme.php +++ b/lib/internal/Magento/Framework/Config/Theme.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Config/etc/view.xsd b/lib/internal/Magento/Framework/Config/etc/view.xsd index 7d826eac5fc0d..72939b3090116 100644 --- a/lib/internal/Magento/Framework/Config/etc/view.xsd +++ b/lib/internal/Magento/Framework/Config/etc/view.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Console/Cli.php b/lib/internal/Magento/Framework/Console/Cli.php index 4da186fcf8864..5f3a4cb23e6d4 100644 --- a/lib/internal/Magento/Framework/Console/Cli.php +++ b/lib/internal/Magento/Framework/Console/Cli.php @@ -1,106 +1,110 @@ serviceManager = \Zend\Mvc\Application::init(require BP . '/setup/config/application.config.php') ->getServiceManager(); - $generationDirectoryAccess = new GenerationDirectoryAccess($this->serviceManager); - if (!$generationDirectoryAccess->check()) { - $output = new ConsoleOutput(); - $output->writeln( - 'Command line user does not have read and write permissions on var/generation directory. Please' - . ' address this issue before using Magento command line.' - ); - exit(0); - } - /** - * Temporary workaround until the compiler is able to clear the generation directory - * @todo remove after MAGETWO-44493 resolved - */ - if (class_exists(CompilerPreparation::class)) { - $compilerPreparation = new CompilerPreparation($this->serviceManager, new ArgvInput(), new File()); - $compilerPreparation->handleCompilerEnvironment(); - } + + $this->assertCompilerPreparation(); + $this->initObjectManager(); + $this->assertGenerationPermissions(); if ($version == 'UNKNOWN') { - $directoryList = new DirectoryList(BP); + $directoryList = new DirectoryList(BP); $composerJsonFinder = new ComposerJsonFinder($directoryList); - $productMetadata = new ProductMetadata($composerJsonFinder); + $productMetadata = new ProductMetadata($composerJsonFinder); $version = $productMetadata->getVersion(); } + parent::__construct($name, $version); } /** - * Process an error happened during initialization of commands, if any + * {@inheritdoc} * - * @param InputInterface $input - * @param OutputInterface $output - * @return int - * @throws \Exception + * @throws \Exception the exception in case of unexpected error */ - public function doRun(InputInterface $input, OutputInterface $output) + public function doRun(Console\Input\InputInterface $input, Console\Output\OutputInterface $output) { $exitCode = parent::doRun($input, $output); + if ($this->initException) { $output->writeln( "We're sorry, an error occurred. Try clearing the cache and code generation directories. " - . "By default, they are: var/cache, var/di, var/generation, and var/page_cache." + . "By default, they are: " . $this->getDefaultDirectoryPath(DirectoryList::CACHE) . ", " + . $this->getDefaultDirectoryPath(DirectoryList::GENERATED_METADATA) . ", " + . $this->getDefaultDirectoryPath(DirectoryList::GENERATED_CODE) . ", and var/page_cache." ); + throw $this->initException; } + return $exitCode; } @@ -113,46 +117,142 @@ protected function getDefaultCommands() } /** - * Gets application commands + * Gets application commands. * - * @return array + * @return array a list of available application commands */ protected function getApplicationCommands() { $commands = []; try { - $bootstrapParam = new ComplexParameter(self::INPUT_KEY_BOOTSTRAP); - $params = $bootstrapParam->mergeFromArgv($_SERVER, $_SERVER); - $params[Bootstrap::PARAM_REQUIRE_MAINTENANCE] = null; - $bootstrap = Bootstrap::create(BP, $params); - $objectManager = $bootstrap->getObjectManager(); - /** @var \Magento\Setup\Model\ObjectManagerProvider $omProvider */ - $omProvider = $this->serviceManager->get(\Magento\Setup\Model\ObjectManagerProvider::class); - $omProvider->setObjectManager($objectManager); - if (class_exists(\Magento\Setup\Console\CommandList::class)) { $setupCommandList = new \Magento\Setup\Console\CommandList($this->serviceManager); $commands = array_merge($commands, $setupCommandList->getCommands()); } - if ($objectManager->get(\Magento\Framework\App\DeploymentConfig::class)->isAvailable()) { - /** @var \Magento\Framework\Console\CommandListInterface */ - $commandList = $objectManager->create(\Magento\Framework\Console\CommandListInterface::class); + if ($this->objectManager->get(DeploymentConfig::class)->isAvailable()) { + /** @var CommandListInterface */ + $commandList = $this->objectManager->create(CommandListInterface::class); $commands = array_merge($commands, $commandList->getCommands()); } - $commands = array_merge($commands, $this->getVendorCommands($objectManager)); + $commands = array_merge( + $commands, + $this->getVendorCommands($this->objectManager) + ); } catch (\Exception $e) { $this->initException = $e; } + return $commands; } /** - * Gets vendor commands + * Object Manager initialization. * - * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @return array + * @return void + * @SuppressWarnings(PHPMD.ExitExpression) + */ + private function initObjectManager() + { + try { + $params = (new ComplexParameter(self::INPUT_KEY_BOOTSTRAP))->mergeFromArgv($_SERVER, $_SERVER); + $params[Bootstrap::PARAM_REQUIRE_MAINTENANCE] = null; + + $this->objectManager = Bootstrap::create(BP, $params)->getObjectManager(); + + /** @var ObjectManagerProvider $omProvider */ + $omProvider = $this->serviceManager->get(ObjectManagerProvider::class); + $omProvider->setObjectManager($this->objectManager); + } catch (FileSystemException $exception) { + $this->writeGenerationDirectoryReadError(); + + exit(static::RETURN_FAILURE); + } + } + + /** + * Checks whether generation directory is read-only. + * Depends on the current mode: + * production - application will proceed + * default - application will be terminated + * developer - application will be terminated + * + * @return void + * @SuppressWarnings(PHPMD.ExitExpression) + */ + private function assertGenerationPermissions() + { + /** @var GenerationDirectoryAccess $generationDirectoryAccess */ + $generationDirectoryAccess = $this->objectManager->create( + GenerationDirectoryAccess::class, + ['serviceManager' => $this->serviceManager] + ); + /** @var State $state */ + $state = $this->objectManager->get(State::class); + + if ( + $state->getMode() !== State::MODE_PRODUCTION + && !$generationDirectoryAccess->check() + ) { + $this->writeGenerationDirectoryReadError(); + + exit(static::RETURN_FAILURE); + } + } + + /** + * Checks whether compiler is being prepared. + * + * @return void + * @SuppressWarnings(PHPMD.ExitExpression) + */ + private function assertCompilerPreparation() + { + /** + * Temporary workaround until the compiler is able to clear the generation directory + * @todo remove after MAGETWO-44493 resolved + */ + if (class_exists(CompilerPreparation::class)) { + $compilerPreparation = new CompilerPreparation( + $this->serviceManager, + new Console\Input\ArgvInput(), + new File() + ); + + try { + $compilerPreparation->handleCompilerEnvironment(); + } catch (FileSystemException $e) { + $this->writeGenerationDirectoryReadError(); + + exit(static::RETURN_FAILURE); + } + } + } + + /** + * Writes read error to console. + * + * @return void + */ + private function writeGenerationDirectoryReadError() + { + $output = new \Symfony\Component\Console\Output\ConsoleOutput(); + $output->writeln( + '' + . 'Command line user does not have read and write permissions on ' + . $this->getDefaultDirectoryPath(DirectoryList::GENERATED_CODE) . ' directory. ' + . 'Please address this issue before using Magento command line.' + . '' + ); + } + + /** + * Retrieves vendor commands. + * + * @param ObjectManagerInterface $objectManager the object manager + * + * @return array an array with external commands */ protected function getVendorCommands($objectManager) { @@ -165,6 +265,25 @@ protected function getVendorCommands($objectManager) ); } } + return $commands; } + + /** + * Get default directory path by code + * + * @param string $code + * @return string + */ + private function getDefaultDirectoryPath($code) + { + $config = DirectoryList::getDefaultConfig(); + $result = ''; + + if (isset($config[$code][DirectoryList::PATH])) { + $result = $config[$code][DirectoryList::PATH]; + } + + return $result; + } } diff --git a/lib/internal/Magento/Framework/Console/CommandList.php b/lib/internal/Magento/Framework/Console/CommandList.php index 0329802879b6f..8a51403fb1ebd 100644 --- a/lib/internal/Magento/Framework/Console/CommandList.php +++ b/lib/internal/Magento/Framework/Console/CommandList.php @@ -1,6 +1,6 @@ getPath(DirectoryList::GENERATION); + $generationDirectoryPath = $directoryList->getPath(DirectoryList::GENERATED_CODE); $driverPool = new DriverPool(); $fileWriteFactory = new WriteFactory($driverPool); /** @var \Magento\Framework\Filesystem\DriverInterface $driver */ diff --git a/lib/internal/Magento/Framework/Controller/AbstractResult.php b/lib/internal/Magento/Framework/Controller/AbstractResult.php index afcd4c776dccd..b6a979443a4af 100644 --- a/lib/internal/Magento/Framework/Controller/AbstractResult.php +++ b/lib/internal/Magento/Framework/Controller/AbstractResult.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Convert/Xml.php b/lib/internal/Magento/Framework/Convert/Xml.php index ce2f203ee14e9..a836206db0882 100644 --- a/lib/internal/Magento/Framework/Convert/Xml.php +++ b/lib/internal/Magento/Framework/Convert/Xml.php @@ -1,6 +1,6 @@ shell = $shell; + $this->filesystem = $filesystem; + } + + /** + * {@inheritdoc} + */ + public function getTasks() + { + $this->checkSupportedOs(); + $content = $this->getCrontabContent(); + $pattern = '!(' . self::TASKS_BLOCK_START . ')(.*?)(' . self::TASKS_BLOCK_END . ')!s'; + + if (preg_match($pattern, $content, $matches)) { + $tasks = trim($matches[2], PHP_EOL); + $tasks = explode(PHP_EOL, $tasks); + return $tasks; + } + + return []; + } + + /** + * {@inheritdoc} + */ + public function saveTasks(array $tasks) + { + $this->checkSupportedOs(); + $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); + $logDir = $this->filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath(); + + if (!$tasks) { + throw new LocalizedException(new Phrase('List of tasks is empty')); + } + + foreach ($tasks as $key => $task) { + if (empty($task['expression'])) { + $tasks[$key]['expression'] = '* * * * *'; + } + + if (empty($task['command'])) { + throw new LocalizedException(new Phrase('Command should not be empty')); + } + + $tasks[$key]['command'] = str_replace( + ['{magentoRoot}', '{magentoLog}'], + [$baseDir, $logDir], + $task['command'] + ); + } + + $content = $this->getCrontabContent(); + $content = $this->cleanMagentoSection($content); + $content = $this->generateSection($content, $tasks); + + $this->save($content); + } + + /** + * {@inheritdoc} + * @throws LocalizedException + */ + public function removeTasks() + { + $this->checkSupportedOs(); + $content = $this->getCrontabContent(); + $content = $this->cleanMagentoSection($content); + $this->save($content); + } + + /** + * Generate Magento Tasks Section + * + * @param string $content + * @param array $tasks + * @return string + */ + private function generateSection($content, $tasks = []) + { + if ($tasks) { + $content .= self::TASKS_BLOCK_START . PHP_EOL; + foreach ($tasks as $task) { + $content .= $task['expression'] . ' ' . PHP_BINARY . ' '. $task['command'] . PHP_EOL; + } + $content .= self::TASKS_BLOCK_END . PHP_EOL; + } + + return $content; + } + + /** + * Clean Magento Tasks Section in crontab content + * + * @param string $content + * @return string + */ + private function cleanMagentoSection($content) + { + $content = preg_replace( + '!' . preg_quote(self::TASKS_BLOCK_START) . '.*?' . preg_quote(self::TASKS_BLOCK_END . PHP_EOL) . '!s', + '', + $content + ); + + return $content; + } + + /** + * Get crontab content without Magento Tasks Section + * + * In case of some exceptions the empty content is returned + * + * @return string + */ + private function getCrontabContent() + { + try { + $content = (string)$this->shell->execute('crontab -l'); + } catch (LocalizedException $e) { + return ''; + } + + return $content; + } + + /** + * Save crontab + * + * @param string $content + * @return void + * @throws LocalizedException + */ + private function save($content) + { + $content = str_replace('%', '%%', $content); + + try { + $this->shell->execute('echo "' . $content . '" | crontab -'); + } catch (LocalizedException $e) { + throw new LocalizedException( + new Phrase('Error during saving of crontab: %1', [$e->getPrevious()->getMessage()]), + $e + ); + } + } + + /** + * Check that OS is supported + * + * If OS is not supported then no possibility to work with crontab + * + * @return void + * @throws LocalizedException + */ + private function checkSupportedOs() + { + if (stripos(PHP_OS, 'WIN') === 0) { + throw new LocalizedException( + new Phrase('Your operation system is not supported to work with this command') + ); + } + } +} diff --git a/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php b/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php new file mode 100644 index 0000000000000..cde6f3f11fe20 --- /dev/null +++ b/lib/internal/Magento/Framework/Crontab/CrontabManagerInterface.php @@ -0,0 +1,43 @@ +tasks = $tasks; + } + + /** + * {@inheritdoc} + */ + public function getTasks() + { + return $this->tasks; + } +} diff --git a/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php b/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php new file mode 100644 index 0000000000000..f3384365f4bfb --- /dev/null +++ b/lib/internal/Magento/Framework/Crontab/TasksProviderInterface.php @@ -0,0 +1,16 @@ +shellMock = $this->getMockBuilder(ShellInterface::class) + ->getMockForAbstractClass(); + $this->filesystemMock = $this->getMockBuilder(Filesystem::class) + ->disableOriginalClone() + ->disableOriginalConstructor() + ->getMock(); + + $this->crontabManager = new CrontabManager($this->shellMock, $this->filesystemMock); + } + + /** + * @return void + */ + public function testGetTasksNoCrontab() + { + $exception = new \Exception('crontab: no crontab for user'); + $localizedException = new LocalizedException(new Phrase('Some error'), $exception); + + $this->shellMock->expects($this->once()) + ->method('execute') + ->with('crontab -l', []) + ->willThrowException($localizedException); + + $this->assertEquals([], $this->crontabManager->getTasks()); + } + + /** + * @param string $content + * @param array $tasks + * @return void + * @dataProvider getTasksDataProvider + */ + public function testGetTasks($content, $tasks) + { + $this->shellMock->expects($this->once()) + ->method('execute') + ->with('crontab -l', []) + ->willReturn($content); + + $this->assertEquals($tasks, $this->crontabManager->getTasks()); + } + + /** + * @return array + */ + public function getTasksDataProvider() + { + return [ + [ + 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'tasks' => ['* * * * * /bin/php /var/www/magento/bin/magento cron:run'], + ], + [ + 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'tasks' => [ + '* * * * * /bin/php /var/www/magento/bin/magento cron:run', + '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run', + ], + ], + [ + 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL, + 'tasks' => [], + ], + [ + 'content' => '', + 'tasks' => [], + ], + ]; + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Shell error + */ + public function testRemoveTasksWithException() + { + $exception = new \Exception('Shell error'); + $localizedException = new LocalizedException(new Phrase('Some error'), $exception); + + $this->shellMock->expects($this->at(0)) + ->method('execute') + ->with('crontab -l', []) + ->willReturn(''); + + $this->shellMock->expects($this->at(1)) + ->method('execute') + ->with('echo "" | crontab -', []) + ->willThrowException($localizedException); + + $this->crontabManager->removeTasks(); + } + + /** + * @param string $contentBefore + * @param string $contentAfter + * @return void + * @dataProvider removeTasksDataProvider + */ + public function testRemoveTasks($contentBefore, $contentAfter) + { + $this->shellMock->expects($this->at(0)) + ->method('execute') + ->with('crontab -l', []) + ->willReturn($contentBefore); + + $this->shellMock->expects($this->at(1)) + ->method('execute') + ->with('echo "' . $contentAfter . '" | crontab -', []); + + $this->crontabManager->removeTasks(); + } + + /** + * @return array + */ + public function removeTasksDataProvider() + { + return [ + [ + 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + ], + [ + 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + ], + [ + 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL, + 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + ], + [ + 'contentBefore' => '', + 'contentAfter' => '' + ], + ]; + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage List of tasks is empty + */ + public function testSaveTasksWithEmptyTasksList() + { + $baseDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $baseDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/'); + $logDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $logDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/var/log/'); + + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->willReturnMap([ + [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock], + [DirectoryList::LOG, DriverPool::FILE, $logDirMock], + ]); + + $this->crontabManager->saveTasks([]); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Command should not be empty + */ + public function testSaveTasksWithoutCommand() + { + $baseDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $baseDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/'); + $logDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $logDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/var/log/'); + + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->willReturnMap([ + [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock], + [DirectoryList::LOG, DriverPool::FILE, $logDirMock], + ]); + + $this->crontabManager->saveTasks([ + 'myCron' => ['expression' => '* * * * *'] + ]); + } + + /** + * @param array $tasks + * @param string $content + * @param string $contentToSave + * @return void + * @dataProvider saveTasksDataProvider + */ + public function testSaveTasks($tasks, $content, $contentToSave) + { + $baseDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $baseDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/'); + $logDirMock = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $logDirMock->expects($this->once()) + ->method('getAbsolutePath') + ->willReturn('/var/www/magento2/var/log/'); + + $this->filesystemMock->expects($this->any()) + ->method('getDirectoryRead') + ->willReturnMap([ + [DirectoryList::ROOT, DriverPool::FILE, $baseDirMock], + [DirectoryList::LOG, DriverPool::FILE, $logDirMock], + ]); + + $this->shellMock->expects($this->at(0)) + ->method('execute') + ->with('crontab -l', []) + ->willReturn($content); + + $this->shellMock->expects($this->at(1)) + ->method('execute') + ->with('echo "' . $contentToSave . '" | crontab -', []); + + $this->crontabManager->saveTasks($tasks); + } + + /** + * @return array + */ + public function saveTasksDataProvider() + { + $content = '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL; + + return [ + [ + 'tasks' => [ + ['expression' => '* * * * *', 'command' => 'run.php'] + ], + 'content' => $content, + 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * ' . PHP_BINARY . ' run.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + ], + [ + 'tasks' => [ + ['expression' => '1 2 3 4 5', 'command' => 'run.php'] + ], + 'content' => $content, + 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '1 2 3 4 5 ' . PHP_BINARY . ' run.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + ], + [ + 'tasks' => [ + ['command' => '{magentoRoot}run.php >> {magentoLog}cron.log'] + ], + 'content' => $content, + 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . '* * * * * ' . PHP_BINARY . ' /var/www/magento2/run.php >>' + . ' /var/www/magento2/var/log/cron.log' . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php b/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php new file mode 100644 index 0000000000000..c5c45efe230ac --- /dev/null +++ b/lib/internal/Magento/Framework/Crontab/Test/Unit/TasksProviderTest.php @@ -0,0 +1,34 @@ +assertSame([], $tasksProvider->getTasks()); + } + + public function testTasksProvider() + { + $tasks = [ + 'magentoCron' => ['expressin' => '* * * * *', 'command' => 'bin/magento cron:run'], + 'magentoSetup' => ['command' => 'bin/magento setup:cron:run'], + ]; + + /** @var $tasksProvider $tasksProvider */ + $tasksProvider = new TasksProvider($tasks); + $this->assertSame($tasks, $tasksProvider->getTasks()); + } +} diff --git a/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/Less/Processor.php b/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/Less/Processor.php index 49d2545ea5bb8..44d8abb31436e 100644 --- a/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/Less/Processor.php +++ b/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/Less/Processor.php @@ -1,6 +1,6 @@ temporaryFile->createFile($path, $content); - $parser->parseFile($tmpFilePath, ''); + gc_disable(); + $parser->parseFile($tmpFilePath, ''); $content = $parser->getCss(); + gc_enable(); if (trim($content) === '') { $errorMessage = PHP_EOL . self::ERROR_MESSAGE_PREFIX . PHP_EOL . $path; diff --git a/lib/internal/Magento/Framework/Css/PreProcessor/Config.php b/lib/internal/Magento/Framework/Css/PreProcessor/Config.php index 9aaa2b5067669..51eb8a979396e 100644 --- a/lib/internal/Magento/Framework/Css/PreProcessor/Config.php +++ b/lib/internal/Magento/Framework/Css/PreProcessor/Config.php @@ -1,6 +1,6 @@ \w+)\)\s+)?[\'\"](?P(?![/\\\]|\w:[/\\\])[^\"\']+)[\'\"]\s*?(?P.*?);#'; + '#@import(?!.*?\surl\(.*?)' + . '(?P[\(\),\w\s]*?[\'\"])' + . '(?P(?![/\\\]|\w*?:[/\\\])[^\"\']+)' + . '(?P[\'\"][\s\w\(\)]*?);#'; /** * @var \Magento\Framework\View\Asset\NotationResolver\Module @@ -133,9 +134,9 @@ protected function replace(array $matchedContent, LocalInterface $asset, $conten $matchedFileId = $this->fixFileExtension($matchedContent['path'], $contentType); $this->recordRelatedFile($matchedFileId, $asset); $resolvedPath = $this->notationResolver->convertModuleNotationToPath($asset, $matchedFileId); - $typeString = empty($matchedContent['type']) ? '' : '(' . $matchedContent['type'] . ') '; - $mediaString = empty($matchedContent['media']) ? '' : ' ' . trim($matchedContent['media']); - return "@import {$typeString}'{$resolvedPath}'{$mediaString};"; + $start = $matchedContent['start']; + $end = $matchedContent['end']; + return "@import{$start}{$resolvedPath}{$end};"; } /** diff --git a/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/MagentoImport.php b/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/MagentoImport.php index a07c7eea16aeb..2a8bc7a0a4efd 100644 --- a/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/MagentoImport.php +++ b/lib/internal/Magento/Framework/Css/PreProcessor/Instruction/MagentoImport.php @@ -1,19 +1,22 @@ getContext(); if ($context instanceof FallbackContext) { - return $this->themeList->getThemeByFullPath($context->getAreaCode() . '/' . $context->getThemePath()); + return $this->getThemeProvider()->getThemeByFullPath( + $context->getAreaCode() . '/' . $context->getThemePath() + ); } return $this->design->getDesignTheme(); } + + /** + * @return ThemeProviderInterface + * @deprecated + */ + private function getThemeProvider() + { + if (null === $this->themeProvider) { + $this->themeProvider = ObjectManager::getInstance()->get(ThemeProviderInterface::class); + } + + return $this->themeProvider; + } } diff --git a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Adapter/Less/ProcessorTest.php b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Adapter/Less/ProcessorTest.php index 4a8f35751bd4c..5943f4c54ad86 100644 --- a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Adapter/Less/ProcessorTest.php +++ b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Adapter/Less/ProcessorTest.php @@ -1,6 +1,6 @@ notationResolver = $this->getMock( + $this->notationResolver = $this->getMock( \Magento\Framework\View\Asset\NotationResolver\Module::class, [], [], '', false ); $this->asset = $this->getMock(\Magento\Framework\View\Asset\File::class, [], [], '', false); @@ -63,7 +63,11 @@ protected function setUp() public function testProcess($originalContent, $foundPath, $resolvedPath, $expectedContent) { $chain = new \Magento\Framework\View\Asset\PreProcessor\Chain($this->asset, $originalContent, 'less', 'path'); - $this->notationResolver->expects($this->once()) + $invoke = $this->once(); + if (preg_match('/^(http:|https:|\/+)/', $foundPath)) { + $invoke = $this->never(); + } + $this->notationResolver->expects($invoke) ->method('convertModuleNotationToPath') ->with($this->asset, $foundPath) ->will($this->returnValue($resolvedPath)); @@ -78,50 +82,70 @@ public function testProcess($originalContent, $foundPath, $resolvedPath, $expect public function processDataProvider() { return [ - 'non-modular notation' => [ - '@import (type) "some/file.css" media;', - 'some/file.css', - 'some/file.css', - "@import (type) 'some/file.css' media;", + 'non-modular notation, no extension' => [ + '@import (type) \'some/file\' media;', + 'some/file.less', + 'some/file.less', + '@import (type) \'some/file.less\' media;', ], 'modular, with extension' => [ '@import (type) "Magento_Module::something.css" media;', 'Magento_Module::something.css', 'Magento_Module/something.css', - "@import (type) 'Magento_Module/something.css' media;", + '@import (type) "Magento_Module/something.css" media;', + ], + 'remote file import url()' => [ + '@import (type) url("http://example.com/css/some.css") media;', + 'http://example.com/css/some.css', + null, + '@import (type) url("http://example.com/css/some.css") media;', + ], + 'invalid path' => [ + '@import (type) url("/example.com/css/some.css") media;', + '/example.com/css/some.css', + null, + '@import (type) url("/example.com/css/some.css") media;', ], 'modular, no extension' => [ '@import (type) "Magento_Module::something" media;', 'Magento_Module::something.less', 'Magento_Module/something.less', - "@import (type) 'Magento_Module/something.less' media;", + '@import (type) "Magento_Module/something.less" media;', ], 'no type' => [ '@import "Magento_Module::something.css" media;', 'Magento_Module::something.css', 'Magento_Module/something.css', - "@import 'Magento_Module/something.css' media;", + '@import "Magento_Module/something.css" media;', ], 'no media' => [ '@import (type) "Magento_Module::something.css";', 'Magento_Module::something.css', 'Magento_Module/something.css', - "@import (type) 'Magento_Module/something.css';", + '@import (type) "Magento_Module/something.css";', + ], + 'with single line comment, replace' => [ + '@import (type) "some/file" media;' . PHP_EOL + . '// @import (type) "unnecessary/file.css" media;', + 'some/file.less', + 'some/file.less', + '@import (type) "some/file.less" media;' . PHP_EOL, ], - 'with single line comment' => [ - '@import (type) "some/file.css" media;' . PHP_EOL - . '// @import (type) "unnecessary/file.css" media;', - 'some/file.css', - 'some/file.css', - "@import (type) 'some/file.css' media;" . PHP_EOL, + 'with single line comment, no replace' => [ + '@import (type) "some/file.less" media;' . PHP_EOL + . '// @import (type) "unnecessary/file" media;', + 'some/file.less', + 'some/file.less', + '@import (type) "some/file.less" media;' . PHP_EOL + . '// @import (type) "unnecessary/file" media;', ], 'with multi line comment' => [ - '@import (type) "some/file.css" media;' . PHP_EOL + '@import (type) "some/file" media;' . PHP_EOL . '/* @import (type) "unnecessary/file.css" media;' . PHP_EOL . '@import (type) "another/unnecessary/file.css" media; */', - 'some/file.css', - 'some/file.css', - "@import (type) 'some/file.css' media;" . PHP_EOL, + 'some/file.less', + 'some/file.less', + '@import (type) "some/file.less" media;' . PHP_EOL, ], ]; } diff --git a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php index f5c81d78436aa..107505dd71593 100644 --- a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php +++ b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/Instruction/MagentoImportTest.php @@ -1,6 +1,6 @@ asset = $this->getMock(\Magento\Framework\View\Asset\File::class, [], [], '', false); $this->asset->expects($this->any())->method('getContentType')->will($this->returnValue('css')); $this->assetRepo = $this->getMock(\Magento\Framework\View\Asset\Repository::class, [], [], '', false); - $this->themeList = $this->getMockForAbstractClass(\Magento\Framework\View\Design\Theme\ListInterface::class); - $this->object = new \Magento\Framework\Css\PreProcessor\Instruction\MagentoImport( - $this->design, - $this->fileSource, - $this->errorHandler, - $this->assetRepo, - $this->themeList - ); + $this->themeProvider = $this->getMock(ThemeProviderInterface::class); + $this->object = (new ObjectManager($this))->getObject(MagentoImport::class, [ + 'design' => $this->design, + 'fileSource' => $this->fileSource, + 'errorHandler' => $this->errorHandler, + 'assetRepo' => $this->assetRepo, + 'themeProvider' => $this->themeProvider + ]); } /** @@ -91,7 +95,7 @@ public function testProcess($originalContent, $foundPath, $resolvedPath, $foundF ->will($this->returnValue($relatedAsset)); $relatedAsset->expects($this->once())->method('getContext')->will($this->returnValue($context)); $theme = $this->getMockForAbstractClass(\Magento\Framework\View\Design\ThemeInterface::class); - $this->themeList->expects($this->once())->method('getThemeByFullPath')->will($this->returnValue($theme)); + $this->themeProvider->expects($this->once())->method('getThemeByFullPath')->will($this->returnValue($theme)); $files = []; foreach ($foundFiles as $file) { $fileObject = $this->getMock(\Magento\Framework\View\File::class, [], [], '', false); diff --git a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/invalid.less b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/invalid.less index 8a2a6ea346d65..ef8b826cdf8f8 100644 --- a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/invalid.less +++ b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/invalid.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/valid.less b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/valid.less index c50557ac83eef..b0c5c6993df64 100644 --- a/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/valid.less +++ b/lib/internal/Magento/Framework/Css/Test/Unit/PreProcessor/_files/valid.less @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Currency.php b/lib/internal/Magento/Framework/Currency.php index 0d0de1162b7ec..ad613e58ebe2d 100644 --- a/lib/internal/Magento/Framework/Currency.php +++ b/lib/internal/Magento/Framework/Currency.php @@ -1,6 +1,6 @@ LockWaitException::class, // SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock 1213 => DeadlockException::class, + // SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry + 1062 => DuplicateException::class, ]; try { parent::__construct($config); @@ -332,6 +341,9 @@ public function convertDateTime($datetime) /** * Creates a PDO object and connects to the database. * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + * * @return void * @throws \Zend_Db_Adapter_Exception */ @@ -362,6 +374,10 @@ protected function _connect() list($this->_config['host'], $this->_config['port']) = explode(':', $this->_config['host']); } + if (!isset($this->_config['driver_options'][\PDO::MYSQL_ATTR_MULTI_STATEMENTS])) { + $this->_config['driver_options'][\PDO::MYSQL_ATTR_MULTI_STATEMENTS] = false; + } + $this->logger->startTimer(); parent::_connect(); $this->logger->logStats(LoggerInterface::TYPE_CONNECT, ''); @@ -459,7 +475,7 @@ protected function _checkDdlTransaction($sql) * @param mixed $bind An array of data or data itself to bind to the placeholders. * @return \Zend_Db_Statement_Pdo|void * @throws \Zend_Db_Adapter_Exception To re-throw \PDOException. - * @throws LocalizedException In case multiple queries are attempted at once, to protect from SQL injection + * @throws \Zend_Db_Statement_Exception * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ protected function _query($sql, $bind = []) @@ -553,6 +569,7 @@ public function query($sql, $bind = []) * @throws \Zend_Db_Adapter_Exception To re-throw \PDOException. * @throws LocalizedException In case multiple queries are attempted at once, to protect from SQL injection * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @deprecated */ public function multiQuery($sql, $bind = []) { @@ -719,6 +736,8 @@ public function setQueryHook($hook) * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) + + * @deprecated */ protected function _splitMultiQuery($sql) { @@ -1368,7 +1387,6 @@ protected function _removeDuplicateEntry($table, $fields, $ids) */ public function select() { -// return new Select($this); return $this->selectFactory->create($this); } @@ -3362,57 +3380,32 @@ public function insertFromSelect(Select $select, $table, array $fields = [], $mo * @param int $stepCount * @return \Magento\Framework\DB\Select[] * @throws LocalizedException + * @deprecated */ public function selectsByRange($rangeField, \Magento\Framework\DB\Select $select, $stepCount = 100) { - $fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM); - if (empty($fromSelect)) { - throw new LocalizedException( - new \Magento\Framework\Phrase('Select object must have correct "FROM" part') - ); - } - - $tableName = []; - $correlationName = ''; - foreach ($fromSelect as $correlationName => $formPart) { - if ($formPart['joinType'] == \Magento\Framework\DB\Select::FROM) { - $tableName = $formPart['tableName']; - break; - } - } - - $selectRange = $this->select() - ->from( - $tableName, - [ - new \Zend_Db_Expr('MIN(' . $this->quoteIdentifier($rangeField) . ') AS min'), - new \Zend_Db_Expr('MAX(' . $this->quoteIdentifier($rangeField) . ') AS max'), - ] - ); - - $rangeResult = $this->fetchRow($selectRange); - $min = $rangeResult['min']; - $max = $rangeResult['max']; - + $iterator = $this->getQueryGenerator()->generate($rangeField, $select, $stepCount); $queries = []; - while ($min <= $max) { - $partialSelect = clone $select; - $partialSelect->where( - $this->quoteIdentifier($correlationName) . '.' - . $this->quoteIdentifier($rangeField) . ' >= ?', - $min - ) - ->where( - $this->quoteIdentifier($correlationName) . '.' - . $this->quoteIdentifier($rangeField) . ' < ?', - $min + $stepCount - ); - $queries[] = $partialSelect; - $min += $stepCount; + foreach ($iterator as $query) { + $queries[] = $query; } return $queries; } + /** + * Get query generator + * + * @return QueryGenerator + * @deprecated + */ + private function getQueryGenerator() + { + if ($this->queryGenerator === null) { + $this->queryGenerator = \Magento\Framework\App\ObjectManager::getInstance()->create(QueryGenerator::class); + } + return $this->queryGenerator; + } + /** * Get update table query using select object for join and update * diff --git a/lib/internal/Magento/Framework/DB/DataConverter/DataConverterInterface.php b/lib/internal/Magento/Framework/DB/DataConverter/DataConverterInterface.php new file mode 100644 index 0000000000000..129f7155a3faf --- /dev/null +++ b/lib/internal/Magento/Framework/DB/DataConverter/DataConverterInterface.php @@ -0,0 +1,20 @@ +serialize = $serialize; + $this->json = $json; + } + + /** + * Convert from serialized to JSON format + * + * @param string $value + * @return string + */ + public function convert($value) + { + return $this->json->serialize($this->serialize->unserialize($value)); + } +} diff --git a/lib/internal/Magento/Framework/DB/Ddl/Sequence.php b/lib/internal/Magento/Framework/DB/Ddl/Sequence.php index c2f9480d7f599..f776e0dbfde0a 100644 --- a/lib/internal/Magento/Framework/DB/Ddl/Sequence.php +++ b/lib/internal/Magento/Framework/DB/Ddl/Sequence.php @@ -1,6 +1,6 @@ queryGenerator = $queryGenerator; + $this->dataConverter = $dataConverter; + $this->selectFactory = $selectFactory ?: ObjectManager::getInstance()->get(SelectFactory::class); + } + + /** + * Convert table field data from one representation to another uses DataConverterInterface + * + * @param AdapterInterface $connection + * @param string $table + * @param string $identifier + * @param string $field + * @param QueryModifierInterface|null $queryModifier + * @return void + */ + public function convert( + AdapterInterface $connection, + $table, + $identifier, + $field, + QueryModifierInterface $queryModifier = null + ) { + $select = $this->selectFactory->create($connection) + ->from($table, [$identifier, $field]) + ->where($field . ' IS NOT NULL'); + if ($queryModifier) { + $queryModifier->modify($select); + } + $iterator = $this->queryGenerator->generate($identifier, $select); + foreach ($iterator as $selectByRange) { + $rows = $connection->fetchAll($selectByRange); + foreach ($rows as $row) { + $bind = [$field => $this->dataConverter->convert($row[$field])]; + $where = [$identifier . ' = ?' => (int) $row[$identifier]]; + $connection->update($table, $bind, $where); + } + } + } +} diff --git a/lib/internal/Magento/Framework/DB/FieldDataConverterFactory.php b/lib/internal/Magento/Framework/DB/FieldDataConverterFactory.php new file mode 100644 index 0000000000000..76eeba8fa72b7 --- /dev/null +++ b/lib/internal/Magento/Framework/DB/FieldDataConverterFactory.php @@ -0,0 +1,46 @@ +objectManager = $objectManager; + } + + /** + * Create instance of FieldDataConverter + * + * @param string $dataConverterClassName + * @return FieldDataConverter + */ + public function create($dataConverterClassName) + { + return $this->objectManager->create( + FieldDataConverter::class, + [ + 'dataConverter' => $this->objectManager->get($dataConverterClassName) + ] + ); + } +} diff --git a/lib/internal/Magento/Framework/DB/GenericMapper.php b/lib/internal/Magento/Framework/DB/GenericMapper.php index 319d90d660387..8d9c245f63e46 100644 --- a/lib/internal/Magento/Framework/DB/GenericMapper.php +++ b/lib/internal/Magento/Framework/DB/GenericMapper.php @@ -1,6 +1,6 @@ batchSize = $batchSize; + $this->select = $select; + $this->correlationName = $correlationName; + $this->rangeField = $rangeField; + $this->rangeFieldAlias = $rangeFieldAlias; + $this->connection = $select->getConnection(); + } + + /** + * @return Select + */ + public function current() + { + if (null == $this->currentSelect) { + $this->currentSelect = $this->initSelectObject(); + $itemsCount = $this->calculateBatchSize($this->currentSelect); + $this->isValid = $itemsCount > 0; + } + return $this->currentSelect; + } + + /** + * @return Select + */ + public function next() + { + if (null == $this->currentSelect) { + $this->current(); + } + $select = $this->initSelectObject(); + $itemsCountInSelect = $this->calculateBatchSize($select); + $this->isValid = $itemsCountInSelect > 0; + if ($this->isValid) { + $this->iteration++; + $this->currentSelect = $select; + } else { + $this->currentSelect = null; + } + return $this->currentSelect; + } + + /** + * @return int + */ + public function key() + { + return $this->iteration; + } + + /** + * @return bool + */ + public function valid() + { + return $this->isValid; + } + + /** + * @return void + */ + public function rewind() + { + $this->minValue = 0; + $this->currentSelect = null; + $this->iteration = 0; + $this->isValid = true; + } + + /** + * Calculate batch size for select. + * + * @param Select $select + * @return int + */ + private function calculateBatchSize(Select $select) + { + $wrapperSelect = $this->connection->select(); + $wrapperSelect->from( + $select, + [ + new \Zend_Db_Expr('MAX(' . $this->rangeFieldAlias . ') as max'), + new \Zend_Db_Expr('COUNT(*) as cnt') + ] + ); + $row = $this->connection->fetchRow($wrapperSelect); + $this->minValue = $row['max']; + return intval($row['cnt']); + } + + /** + * Initialize select object. + * + * @return \Magento\Framework\DB\Select + */ + private function initSelectObject() + { + $object = clone $this->select; + $object->where( + $this->connection->quoteIdentifier($this->correlationName) + . '.' . $this->connection->quoteIdentifier($this->rangeField) + . ' > ?', + $this->minValue + ); + $object->limit($this->batchSize); + /** + * Reset sort order section from origin select object + */ + $object->order($this->correlationName . '.' . $this->rangeField . ' ' . \Magento\Framework\DB\Select::SQL_ASC); + return $object; + } +} diff --git a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php new file mode 100644 index 0000000000000..147e65b8df466 --- /dev/null +++ b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php @@ -0,0 +1,51 @@ +objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\DB\Query\BatchIterator + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/DB/Query/Generator.php b/lib/internal/Magento/Framework/DB/Query/Generator.php new file mode 100644 index 0000000000000..909f4752397a3 --- /dev/null +++ b/lib/internal/Magento/Framework/DB/Query/Generator.php @@ -0,0 +1,79 @@ +iteratorFactory = $iteratorFactory; + } + + /** + * Generate select query list with predefined items count in each select item. + * + * @param string $rangeField + * @param \Magento\Framework\DB\Select $select + * @param int $batchSize + * @return BatchIterator + * @throws LocalizedException + */ + public function generate($rangeField, \Magento\Framework\DB\Select $select, $batchSize = 100) + { + $fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM); + if (empty($fromSelect)) { + throw new LocalizedException( + new \Magento\Framework\Phrase('Select object must have correct "FROM" part') + ); + } + + $fieldCorrelationName = ''; + foreach ($fromSelect as $correlationName => $fromPart) { + if ($fromPart['joinType'] == \Magento\Framework\DB\Select::FROM) { + $fieldCorrelationName = $correlationName; + break; + } + } + + $columns = $select->getPart(\Magento\Framework\DB\Select::COLUMNS); + /** + * Calculate $rangeField alias + */ + $rangeFieldAlias = $rangeField; + foreach ($columns as $column) { + list($table, $columnName, $alias) = $column; + if ($table == $fieldCorrelationName && $columnName == $rangeField) { + $rangeFieldAlias = $alias ?: $rangeField; + break; + } + } + + return $this->iteratorFactory->create( + [ + 'select' => $select, + 'batchSize' => $batchSize, + 'correlationName' => $fieldCorrelationName, + 'rangeField' => $rangeField, + 'rangeFieldAlias' => $rangeFieldAlias + ] + ); + } +} diff --git a/lib/internal/Magento/Framework/DB/QueryBuilder.php b/lib/internal/Magento/Framework/DB/QueryBuilder.php index 021f5b820eda7..863de90259f36 100644 --- a/lib/internal/Magento/Framework/DB/QueryBuilder.php +++ b/lib/internal/Magento/Framework/DB/QueryBuilder.php @@ -1,6 +1,6 @@ values = $values; + } + + /** + * {@inheritdoc} + */ + public function modify(Select $select) + { + foreach ($this->values as $field => $values) { + $select->where($field . ' IN (?)', $values); + } + } +} diff --git a/lib/internal/Magento/Framework/DB/Select/LimitRenderer.php b/lib/internal/Magento/Framework/DB/Select/LimitRenderer.php index 22409dd36c6a8..0334e350bcf3f 100644 --- a/lib/internal/Magento/Framework/DB/Select/LimitRenderer.php +++ b/lib/internal/Magento/Framework/DB/Select/LimitRenderer.php @@ -1,6 +1,6 @@ objectManager = $objectManager; + $this->queryModifiers = $queryModifiers; + } + + /** + * Create instance of QueryModifierInterface + * + * @param string $type + * @param array $data + * @return QueryModifierInterface + * @throws \InvalidArgumentException + */ + public function create($type, array $data = []) + { + if (!isset($this->queryModifiers[$type])) { + throw new \InvalidArgumentException('Unknown query modifier type ' . $type); + } + $queryModifier = $this->objectManager->create($this->queryModifiers[$type], $data); + if (!($queryModifier instanceof QueryModifierInterface)) { + throw new \InvalidArgumentException( + $this->queryModifiers[$type] . ' must implement ' . QueryModifierInterface::class + ); + } + return $queryModifier; + } +} diff --git a/lib/internal/Magento/Framework/DB/Select/QueryModifierInterface.php b/lib/internal/Magento/Framework/DB/Select/QueryModifierInterface.php new file mode 100644 index 0000000000000..b5c53e207153e --- /dev/null +++ b/lib/internal/Magento/Framework/DB/Select/QueryModifierInterface.php @@ -0,0 +1,22 @@ +random = $random; + $this->allowedIndexMethods = $allowedIndexMethods; + $this->allowedEngines = $allowedEngines; + } + + /** + * Creates a temporary table from select removing duplicate rows if you have a union in your select + * This method should always be paired with dropTable to ensure cleanup + * Make sure you index your data so you can query it fast + * You can choose from memory or file table and provide indexes to ensure fast data query + * + * Example: createFromSelect( + * $selectObject, + * $this->resourceConnection->getConnection(), + * [ + * 'PRIMARY' => ['primary_id'], + * 'some_single_field_index' => ['field'], + * 'UNQ_some_multiple_field_index' => ['field1', 'field2'], + * ] + * ) + * Note that indexes names with UNQ_ prefix, will be created as unique + * + * @param Select $select + * @param AdapterInterface $adapter + * @param array $indexes + * @param string $indexMethod + * @param string $dbEngine + * @return string + * @throws \InvalidArgumentException + */ + public function createFromSelect( + Select $select, + AdapterInterface $adapter, + array $indexes = [], + $indexMethod = self::INDEX_METHOD_HASH, + $dbEngine = self::DB_ENGINE_INNODB + ) { + if (!in_array($indexMethod, $this->allowedIndexMethods)) { + throw new \InvalidArgumentException( + sprintf('indexMethod must be one of %s', implode(',', $this->allowedIndexMethods)) + ); + } + + if (!in_array($dbEngine, $this->allowedEngines)) { + throw new \InvalidArgumentException( + sprintf('dbEngine must be one of %s', implode(',', $this->allowedEngines)) + ); + } + + $name = $this->random->getUniqueHash('tmp_select_'); + + $indexStatements = []; + foreach ($indexes as $indexName => $columns) { + $renderedColumns = implode(',', array_map([$adapter, 'quoteIdentifier'], $columns)); + + $indexType = sprintf( + 'INDEX %s USING %s', + $adapter->quoteIdentifier($indexName), + $indexMethod + ); + + if ($indexName === 'PRIMARY') { + $indexType = 'PRIMARY KEY'; + } elseif (strpos($indexName, 'UNQ_') === 0) { + $indexType = sprintf('UNIQUE %s', $adapter->quoteIdentifier($indexName)); + } + + $indexStatements[] = sprintf('%s(%s)', $indexType, $renderedColumns); + } + + $statement = sprintf( + 'CREATE TEMPORARY TABLE %s %s ENGINE=%s IGNORE (%s)', + $adapter->quoteIdentifier($name), + $indexStatements ? '(' . implode(',', $indexStatements) . ')' : '', + $adapter->quoteIdentifier($dbEngine), + "{$select}" + ); + + $adapter->query( + $statement, + $select->getBind() + ); + + $this->createdTableAdapters[$name] = $adapter; + + return $name; + } + + /** + * Method used to drop a table by name + * This class will hold all temporary table names in createdTableAdapters array + * so we can dispose them once we're finished + * + * Example: dropTable($name) + * where $name is a variable that holds the name for a previously created temporary table + * by using "createFromSelect" method + * + * @param string $name + * @return bool + */ + public function dropTable($name) + { + if (!empty($this->createdTableAdapters)) { + if (isset($this->createdTableAdapters[$name]) && !empty($name)) { + $adapter = $this->createdTableAdapters[$name]; + $adapter->dropTemporaryTable($name); + unset($this->createdTableAdapters[$name]); + return true; + } + } + return false; + } +} diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/AbstractMapperTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/AbstractMapperTest.php index c01121595f795..4f1e321a94064 100644 --- a/lib/internal/Magento/Framework/DB/Test/Unit/AbstractMapperTest.php +++ b/lib/internal/Magento/Framework/DB/Test/Unit/AbstractMapperTest.php @@ -1,6 +1,6 @@ serializeMock = $this->getMock(Serialize::class, [], [], '', false); + $this->jsonMock = $this->getMock(Json::class, [], [], '', false); + $this->serializedToJson = $objectManager->getObject( + SerializedToJson::class, + [ + 'serialize' => $this->serializeMock, + 'json' => $this->jsonMock + ] + ); + } + + public function testConvert() + { + $serializedData = 'serialized data'; + $jsonData = 'json data'; + $unserializedData = 'unserialized data'; + $this->serializeMock->expects($this->once()) + ->method('unserialize') + ->with($serializedData) + ->willReturn($unserializedData); + $this->jsonMock->expects($this->once()) + ->method('serialize') + ->with($unserializedData) + ->willReturn($jsonData); + $this->assertEquals($jsonData, $this->serializedToJson->convert($serializedData)); + } +} diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/Ddl/TriggerTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/Ddl/TriggerTest.php index 152760c7cb151..72a86a3547ffd 100644 --- a/lib/internal/Magento/Framework/DB/Test/Unit/Ddl/TriggerTest.php +++ b/lib/internal/Magento/Framework/DB/Test/Unit/Ddl/TriggerTest.php @@ -1,6 +1,6 @@ objectManagerMock = $this->getMock(ObjectManagerInterface::class); + $this->dataConverterMock = $this->getMock(DataConverterInterface::class); + $this->fieldDataConverterFactory = $objectManager->getObject( + FieldDataConverterFactory::class, + [ + 'objectManager' => $this->objectManagerMock + ] + ); + } + + public function testCreate() + { + $dataConverterClassName = 'ClassName'; + $fieldDataConverterInstance = 'field data converter instance'; + $this->objectManagerMock->expects($this->once()) + ->method('get') + ->with($dataConverterClassName) + ->willReturn($this->dataConverterMock); + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with( + FieldDataConverter::class, + [ + 'dataConverter' => $this->dataConverterMock + ] + ) + ->willReturn($fieldDataConverterInstance); + $this->assertEquals( + $fieldDataConverterInstance, + $this->fieldDataConverterFactory->create($dataConverterClassName) + ); + } +} diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterTest.php new file mode 100644 index 0000000000000..8b2f589a0358c --- /dev/null +++ b/lib/internal/Magento/Framework/DB/Test/Unit/FieldDataConverterTest.php @@ -0,0 +1,151 @@ +connectionMock = $this->getMock(AdapterInterface::class); + $this->queryGeneratorMock = $this->getMock(Generator::class, [], [], '', false); + $this->dataConverterMock = $this->getMock(DataConverterInterface::class); + $this->selectMock = $this->getMock(Select::class, [], [], '', false); + $this->queryModifierMock = $this->getMock(QueryModifierInterface::class); + $this->selectFactoryMock = $this->getMockBuilder(SelectFactory::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + $this->fieldDataConverter = $objectManager->getObject( + FieldDataConverter::class, + [ + 'queryGenerator' => $this->queryGeneratorMock, + 'dataConverter' => $this->dataConverterMock, + 'selectFactory' => $this->selectFactoryMock + ] + ); + } + + /** + * @param boolean $useQueryModifier + * @param int $numQueryModifierCalls + * @dataProvider convertDataProvider + */ + public function testConvert($useQueryModifier, $numQueryModifierCalls) + { + $table = 'table'; + $identifier = 'id'; + $field = 'field'; + $where = $field . ' IS NOT NULL'; + $iterator = ['query 1']; + $rows = [ + [ + $identifier => 1, + $field => 'value' + ] + ]; + $convertedValue = 'converted value'; + $this->selectFactoryMock->expects($this->once()) + ->method('create') + ->with($this->connectionMock) + ->willReturn($this->selectMock); + $this->selectMock->expects($this->once()) + ->method('from') + ->with( + $table, + [$identifier, $field] + ) + ->willReturnSelf(); + $this->selectMock->expects($this->once()) + ->method('where') + ->with($where) + ->willReturnSelf(); + $this->queryModifierMock->expects($this->exactly($numQueryModifierCalls)) + ->method('modify') + ->with($this->selectMock); + $this->queryGeneratorMock->expects($this->once()) + ->method('generate') + ->with($identifier, $this->selectMock) + ->willReturn($iterator); + $this->connectionMock->expects($this->once()) + ->method('fetchAll') + ->with($iterator[0]) + ->willReturn($rows); + $this->dataConverterMock->expects($this->once()) + ->method('convert') + ->with($rows[0][$field]) + ->willReturn($convertedValue); + $this->connectionMock->expects($this->once()) + ->method('update') + ->with( + $table, + [$field => $convertedValue], + [$identifier . ' = ?' => $rows[0][$identifier]] + ); + $this->fieldDataConverter->convert( + $this->connectionMock, + $table, + $identifier, + $field, + $useQueryModifier ? $this->queryModifierMock : null + ); + } + + /** + * @return array + */ + public function convertDataProvider() + { + return [ + [false, 0], + [true, 1] + ]; + } +} diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/GenericMapperTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/GenericMapperTest.php index 2da0cae1bb41c..523894f435748 100644 --- a/lib/internal/Magento/Framework/DB/Test/Unit/GenericMapperTest.php +++ b/lib/internal/Magento/Framework/DB/Test/Unit/GenericMapperTest.php @@ -1,6 +1,6 @@ objectManager = new ObjectManager($this); + $this->objectManagerMock = $this->getMock(ObjectManagerInterface::class); + $this->inQueryModifierMock = $this->getMock(InQueryModifier::class, [], [], '', false); + } + + public function testCreate() + { + $params = ['foo' => 'bar']; + $this->queryModifierFactory = $this->objectManager->getObject( + QueryModifierFactory::class, + [ + 'objectManager' => $this->objectManagerMock, + 'queryModifiers' => [ + 'in' => InQueryModifier::class + ] + ] + ); + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with( + InQueryModifier::class, + $params + ) + ->willReturn($this->inQueryModifierMock); + $this->queryModifierFactory->create('in', $params); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testCreateUnknownQueryModifierType() + { + $params = ['foo' => 'bar']; + $this->queryModifierFactory = $this->objectManager->getObject( + QueryModifierFactory::class, + [ + 'objectManager' => $this->objectManagerMock, + 'queryModifiers' => [] + ] + ); + $this->objectManagerMock->expects($this->never()) + ->method('create'); + $this->queryModifierFactory->create('in', $params); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testCreateDoesNotImplementInterface() + { + $params = ['foo' => 'bar']; + $this->queryModifierFactory = $this->objectManager->getObject( + QueryModifierFactory::class, + [ + 'objectManager' => $this->objectManagerMock, + 'queryModifiers' => [ + 'in' => \stdClass::class + ] + ] + ); + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with( + \stdClass::class, + $params + ) + ->willReturn(new \stdClass()); + $this->queryModifierFactory->create('in', $params); + } +} diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/Select/RendererProxyTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/Select/RendererProxyTest.php index 203146fb650c3..0442b26635098 100644 --- a/lib/internal/Magento/Framework/DB/Test/Unit/Select/RendererProxyTest.php +++ b/lib/internal/Magento/Framework/DB/Test/Unit/Select/RendererProxyTest.php @@ -1,6 +1,6 @@ adapterMock = $this->getMock(AdapterInterface::class); + $this->selectMock = $this->getMock(Select::class, [], [], '', false); + $this->randomMock = $this->getMock(Random::class, [], [], '', false); + $this->temporaryTableService = (new ObjectManager($this))->getObject( + TemporaryTableService::class, + [ + 'random' => $this->randomMock, + 'allowedIndexMethods' => ['HASH'], + 'allowedEngines' => ['INNODB'] + ] + ); + } + + /** + * Run test createFromSelect method + * + * @return void + */ + public function testCreateFromSelectWithException() + { + $this->setExpectedException(\InvalidArgumentException::class); + $random = 'random_table'; + $indexes = [ + ['PRIMARY' => ['primary_column_name']], + 'CREATE TEMPORARY TABLE random_table (PRIMARY KEY(primary_column_name)) ENGINE=INNODB IGNORE ' + . '(select * from sometable)' + ]; + + $this->assertEquals( + $random, + $this->temporaryTableService->createFromSelect( + $this->selectMock, + $this->adapterMock, + $indexes, + TemporaryTableService::INDEX_METHOD_HASH . "Other", + TemporaryTableService::DB_ENGINE_INNODB . "Other" + ) + ); + } + + /** + * Run test createFromSelect method + * + * @param array $indexes + * @param string $expectedSelect + * @dataProvider createFromSelectDataProvider + * @return void + */ + public function testCreateFromSelect($indexes, $expectedSelect) + { + $selectString = 'select * from sometable'; + $random = 'random_table'; + + $this->randomMock->expects($this->once()) + ->method('getUniqueHash') + ->willReturn($random); + + $this->adapterMock->expects($this->once()) + ->method('query') + ->with($expectedSelect) + ->willReturnSelf(); + + $this->adapterMock->expects($this->once()) + ->method('query') + ->willReturnSelf(); + + $this->adapterMock->expects($this->any()) + ->method('quoteIdentifier') + ->willReturnArgument(0); + + $this->selectMock->expects($this->once()) + ->method('getBind') + ->willReturn(['bind']); + + $this->selectMock->expects($this->any()) + ->method('__toString') + ->willReturn($selectString); + + $this->assertEquals( + $random, + $this->temporaryTableService->createFromSelect( + $this->selectMock, + $this->adapterMock, + $indexes + ) + ); + } + + /** + * Run test dropTable method when createdTables array of TemporaryTableService is empty + * + * @return void + */ + public function testDropTableWhenCreatedTablesArrayIsEmpty() + { + $this->assertFalse($this->temporaryTableService->dropTable('tmp_select_table')); + } + + /** + * Run test dropTable method when data exists in createdTables array of TemporaryTableService + * + * @param string $tableName + * @param bool $assertion + * + * @dataProvider dropTableWhenCreatedTablesArrayNotEmptyDataProvider + * @return void + */ + public function testDropTableWhenCreatedTablesArrayNotEmpty($tableName, $assertion) + { + $createdTableAdapters = new \ReflectionProperty($this->temporaryTableService, 'createdTableAdapters'); + $createdTableAdapters->setAccessible(true); + $createdTableAdapters->setValue($this->temporaryTableService, ['tmp_select_table' => $this->adapterMock]); + $createdTableAdapters->setAccessible(false); + + $this->adapterMock->expects($this->any()) + ->method('dropTemporaryTable') + ->willReturn(true); + + $this->assertEquals($this->temporaryTableService->dropTable($tableName), $assertion); + } + + /** + * @return array + */ + public function createFromSelectDataProvider() + { + return [ + [ + ['PRIMARY' => ['primary_column_name']], + 'CREATE TEMPORARY TABLE random_table (PRIMARY KEY(primary_column_name)) ENGINE=INNODB IGNORE ' + . '(select * from sometable)' + ], + [ + ['UNQ_INDX' => ['column1', 'column2']], + 'CREATE TEMPORARY TABLE random_table (UNIQUE UNQ_INDX(column1,column2)) ENGINE=INNODB IGNORE ' + . '(select * from sometable)' + ], + [ + ['OTH_INDX' => ['column3', 'column4']], + 'CREATE TEMPORARY TABLE random_table (INDEX OTH_INDX USING HASH(column3,column4)) ENGINE=INNODB IGNORE ' + . '(select * from sometable)' + ], + [ + [ + 'PRIMARY' => ['primary_column_name'], + 'OTH_INDX' => ['column3', 'column4'], + 'UNQ_INDX' => ['column1', 'column2'] + ], + 'CREATE TEMPORARY TABLE random_table ' + . '(PRIMARY KEY(primary_column_name),' + . 'INDEX OTH_INDX USING HASH(column3,column4),UNIQUE UNQ_INDX(column1,column2)) ENGINE=INNODB IGNORE ' + . '(select * from sometable)' + ], + ]; + } + + /** + * @return array + */ + public function dropTableWhenCreatedTablesArrayNotEmptyDataProvider() + { + return [ + ['tmp_select_table_1', false], + ['tmp_select_table', true], + ]; + } +} diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/Tree/NodeTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/Tree/NodeTest.php index 4ca875170d8d3..e84ad57ae4262 100644 --- a/lib/internal/Magento/Framework/DB/Test/Unit/Tree/NodeTest.php +++ b/lib/internal/Magento/Framework/DB/Test/Unit/Tree/NodeTest.php @@ -2,7 +2,7 @@ /** * \Magento\Framework\DB\Tree\Node test case * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\DB\Test\Unit\Tree; diff --git a/lib/internal/Magento/Framework/DB/Transaction.php b/lib/internal/Magento/Framework/DB/Transaction.php index 7cb374e0c5e27..ad45f5be82e6b 100644 --- a/lib/internal/Magento/Framework/DB/Transaction.php +++ b/lib/internal/Magento/Framework/DB/Transaction.php @@ -2,7 +2,7 @@ /** * DB transaction model * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\DB; diff --git a/lib/internal/Magento/Framework/DB/Tree.php b/lib/internal/Magento/Framework/DB/Tree.php index 88a5aeb6bbe73..1cab446c2d764 100644 --- a/lib/internal/Magento/Framework/DB/Tree.php +++ b/lib/internal/Magento/Framework/DB/Tree.php @@ -1,6 +1,6 @@ sortItems($items); foreach ($items as $itemKey => $itemData) { $result[$itemKey] = $this->itemInterpreter->evaluate($itemData); } return $result; } + + /** + * Sort items by sort order attribute. + * + * @param array $items + * @return array + */ + private function sortItems($items) + { + $sortOrderDefined = $this->isSortOrderDefined($items); + if ($sortOrderDefined) { + $indexedItems = []; + foreach ($items as $key => $item) { + $indexedItems[] = ['key' => $key, 'item' => $item]; + } + uksort( + $indexedItems, + function ($firstItemKey, $secondItemKey) use ($indexedItems) { + return $this->compareItems($firstItemKey, $secondItemKey, $indexedItems); + } + ); + // Convert array of sorted items back to initial format + $items = []; + foreach ($indexedItems as $indexedItem) { + $items[$indexedItem['key']] = $indexedItem['item']; + } + } + return $items; + } + + /** + * Compare sortOrder of item + * + * @param mixed $firstItemKey + * @param mixed $secondItemKey + * @param array $indexedItems + * @return int + */ + private function compareItems($firstItemKey, $secondItemKey, $indexedItems) + { + $firstItem = $indexedItems[$firstItemKey]['item']; + $secondItem = $indexedItems[$secondItemKey]['item']; + $firstValue = 0; + $secondValue = 0; + if (isset($firstItem['sortOrder'])) { + $firstValue = intval($firstItem['sortOrder']); + } + + if (isset($secondItem['sortOrder'])) { + $secondValue = intval($secondItem['sortOrder']); + } + + if ($firstValue == $secondValue) { + // These keys reflect initial relative position of items. + // Allows stable sort for items with equal 'sortOrder' + return $firstItemKey < $secondItemKey ? -1 : 1; + } + return $firstValue < $secondValue ? -1 : 1; + } + + /** + * Determine if a sort order exists for any of the items. + * + * @param array $items + * @return bool + */ + private function isSortOrderDefined($items) + { + foreach ($items as $itemData) { + if (isset($itemData['sortOrder'])) { + return true; + } + } + return false; + } } diff --git a/lib/internal/Magento/Framework/Data/Argument/Interpreter/Boolean.php b/lib/internal/Magento/Framework/Data/Argument/Interpreter/Boolean.php index 731b4f8e95bed..b9fc0e8353114 100644 --- a/lib/internal/Magento/Framework/Data/Argument/Interpreter/Boolean.php +++ b/lib/internal/Magento/Framework/Data/Argument/Interpreter/Boolean.php @@ -1,6 +1,6 @@ * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Data\Helper; diff --git a/lib/internal/Magento/Framework/Data/ObjectFactory.php b/lib/internal/Magento/Framework/Data/ObjectFactory.php index 16ded50588e90..cf2ad968ee15c 100644 --- a/lib/internal/Magento/Framework/Data/ObjectFactory.php +++ b/lib/internal/Magento/Framework/Data/ObjectFactory.php @@ -1,6 +1,6 @@ '-value 3-', ], ], + 'sorted array items' => [ + [ + 'item' => [ + 'key1' => ['value' => 'value 1', 'sortOrder' => 50], + 'key2' => ['value' => 'value 2'], + 'key3' => ['value' => 'value 3', 'sortOrder' => 10], + 'key4' => ['value' => 'value 4'], + ], + ], + [ + 'key2' => '-value 2-', + 'key4' => '-value 4-', + 'key3' => '-value 3-', + 'key1' => '-value 1-', + ], + ], + 'pre-sorted array items' => [ + [ + 'item' => [ + 'key1' => ['value' => 'value 1'], + 'key4' => ['value' => 'value 4'], + 'key2' => ['value' => 'value 2', 'sortOrder' => 10], + 'key3' => ['value' => 'value 3'], + ], + ], + [ + 'key1' => '-value 1-', + 'key4' => '-value 4-', + 'key3' => '-value 3-', + 'key2' => '-value 2-', + ], + ], + 'sort order edge case values' => [ + [ + 'item' => [ + 'key1' => ['value' => 'value 1', 'sortOrder' => 101], + 'key4' => ['value' => 'value 4'], + 'key2' => ['value' => 'value 2', 'sortOrder' => -10], + 'key3' => ['value' => 'value 3'], + 'key5' => ['value' => 'value 5', 'sortOrder' => 20], + ], + ], + [ + 'key2' => '-value 2-', + 'key4' => '-value 4-', + 'key3' => '-value 3-', + 'key5' => '-value 5-', + 'key1' => '-value 1-', + ], + ], ]; } } diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/BooleanTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/BooleanTest.php index 19271928cd428..72f51654c7ec1 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/BooleanTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Argument/Interpreter/BooleanTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Argument/_files/types_valid.xml b/lib/internal/Magento/Framework/Data/Test/Unit/Argument/_files/types_valid.xml index 14666e87393cf..654e11e81b4e4 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Argument/_files/types_valid.xml +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Argument/_files/types_valid.xml @@ -3,7 +3,7 @@ /** * Valid argument types declaration * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Collection/Db/FetchStrategy/CacheTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Collection/Db/FetchStrategy/CacheTest.php index 15485720df3d9..dc99750757c6b 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Collection/Db/FetchStrategy/CacheTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Collection/Db/FetchStrategy/CacheTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/DataObject.php b/lib/internal/Magento/Framework/DataObject.php index 6a4da11d07417..3c5209c579467 100644 --- a/lib/internal/Magento/Framework/DataObject.php +++ b/lib/internal/Magento/Framework/DataObject.php @@ -1,6 +1,6 @@ uuidFactory = $uuidFactory; + public function __construct() + { + $this->uuidFactory = new \Ramsey\Uuid\UuidFactory(); } /** diff --git a/lib/internal/Magento/Framework/DataObject/KeyValueObjectInterface.php b/lib/internal/Magento/Framework/DataObject/KeyValueObjectInterface.php index df7cbf152c8d9..67495a72f5a03 100644 --- a/lib/internal/Magento/Framework/DataObject/KeyValueObjectInterface.php +++ b/lib/internal/Magento/Framework/DataObject/KeyValueObjectInterface.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/_files/fieldset_config.php b/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/_files/fieldset_config.php index 6ad60fb743c89..e127004ba321b 100644 --- a/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/_files/fieldset_config.php +++ b/lib/internal/Magento/Framework/DataObject/Test/Unit/Copy/Config/_files/fieldset_config.php @@ -1,6 +1,6 @@ ramseyFactoryMock = $this->getMock(\Ramsey\Uuid\UuidFactory::class, [], [], '', false); - $this->uuidMock = $this->getMock(\Ramsey\Uuid\Uuid::class, [], [], '', false); - $this->identityService = new \Magento\Framework\DataObject\IdentityService( - $this->ramseyFactoryMock - ); - } - - public function testGenerateId() - { - $this->ramseyFactoryMock->expects($this->once())->method('uuid4')->willReturn($this->uuidMock); - $this->uuidMock->expects($this->once())->method('toString')->willReturn('string'); - $this->assertEquals('string', $this->identityService->generateId()); - } - - public function testGenerateIdForData() - { - $this->ramseyFactoryMock - ->expects($this->once()) - ->method('uuid3') - ->with(Uuid::NAMESPACE_DNS, 'name') - ->willReturn($this->uuidMock); - $this->uuidMock->expects($this->once())->method('toString')->willReturn('string'); - $this->assertEquals('string', $this->identityService->generateIdForData('name')); - } -} diff --git a/lib/internal/Magento/Framework/DataObject/Test/Unit/MapperTest.php b/lib/internal/Magento/Framework/DataObject/Test/Unit/MapperTest.php index 4583d38c5014e..111e09ce279d5 100644 --- a/lib/internal/Magento/Framework/DataObject/Test/Unit/MapperTest.php +++ b/lib/internal/Magento/Framework/DataObject/Test/Unit/MapperTest.php @@ -1,6 +1,6 @@ @@ -66,4 +66,4 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/DataObject/etc/fieldset_file.xsd b/lib/internal/Magento/Framework/DataObject/etc/fieldset_file.xsd index a4dab210ebcb8..a1b04bfca0fb3 100644 --- a/lib/internal/Magento/Framework/DataObject/etc/fieldset_file.xsd +++ b/lib/internal/Magento/Framework/DataObject/etc/fieldset_file.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Debug.php b/lib/internal/Magento/Framework/Debug.php index 09bb44e1af37a..45cc8fe4186c4 100644 --- a/lib/internal/Magento/Framework/Debug.php +++ b/lib/internal/Magento/Framework/Debug.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Encryption/Test/Unit/Crypt/_files/_crypt_fixtures.php b/lib/internal/Magento/Framework/Encryption/Test/Unit/Crypt/_files/_crypt_fixtures.php index 385a6223f08e1..3bc5ff71fc8bd 100644 --- a/lib/internal/Magento/Framework/Encryption/Test/Unit/Crypt/_files/_crypt_fixtures.php +++ b/lib/internal/Magento/Framework/Encryption/Test/Unit/Crypt/_files/_crypt_fixtures.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Encryption/Test/Unit/CryptTest.php b/lib/internal/Magento/Framework/Encryption/Test/Unit/CryptTest.php index 7abc67337ac66..c95ab13ba6496 100644 --- a/lib/internal/Magento/Framework/Encryption/Test/Unit/CryptTest.php +++ b/lib/internal/Magento/Framework/Encryption/Test/Unit/CryptTest.php @@ -1,6 +1,6 @@ describeTable($metadata->getEntityTable()) as $column) { - - if ($column['DEFAULT'] == 'CURRENT_TIMESTAMP') { + $columnName = strtolower($column['COLUMN_NAME']); + if ($this->canNotSetTimeStamp($columnName, $column, $data)) { continue; } - if (isset($data[strtolower($column['COLUMN_NAME'])])) { + + if (isset($data[$columnName])) { $output[strtolower($column['COLUMN_NAME'])] = $data[strtolower($column['COLUMN_NAME'])]; } elseif ($column['DEFAULT'] === null) { $output[strtolower($column['COLUMN_NAME'])] = null; @@ -66,6 +67,18 @@ protected function prepareData(EntityMetadataInterface $metadata, AdapterInterfa return $output; } + /** + * @param string $columnName + * @param string $column + * @param array $data + * @return bool + */ + private function canNotSetTimeStamp($columnName, $column, array $data) + { + return $column['DEFAULT'] == 'CURRENT_TIMESTAMP' && !isset($data[$columnName]) + && empty($column['NULLABLE']); + } + /** * @param string $entityType * @param array $data diff --git a/lib/internal/Magento/Framework/EntityManager/Db/DeleteRow.php b/lib/internal/Magento/Framework/EntityManager/Db/DeleteRow.php index 648ab6f08d521..d7deedcf8e179 100644 --- a/lib/internal/Magento/Framework/EntityManager/Db/DeleteRow.php +++ b/lib/internal/Magento/Framework/EntityManager/Db/DeleteRow.php @@ -1,6 +1,6 @@ describeTable($metadata->getEntityTable()) as $column) { - if ($column['DEFAULT'] == 'CURRENT_TIMESTAMP' || $column['IDENTITY']) { + $columnName = strtolower($column['COLUMN_NAME']); + if ($this->canNotSetTimeStamp($columnName, $column, $data) || $column['IDENTITY']) { continue; } - if (isset($data[strtolower($column['COLUMN_NAME'])])) { + if (isset($data[$columnName])) { $output[strtolower($column['COLUMN_NAME'])] = $data[strtolower($column['COLUMN_NAME'])]; } elseif (!empty($column['NULLABLE'])) { $output[strtolower($column['COLUMN_NAME'])] = null; @@ -67,6 +68,18 @@ protected function prepareData(EntityMetadataInterface $metadata, AdapterInterfa return $output; } + /** + * @param string $columnName + * @param string $column + * @param array $data + * @return bool + */ + private function canNotSetTimeStamp($columnName, $column, array $data) + { + return $column['DEFAULT'] == 'CURRENT_TIMESTAMP' && !isset($data[$columnName]) + && empty($column['NULLABLE']); + } + /** * @param string $entityType * @param array $data diff --git a/lib/internal/Magento/Framework/EntityManager/EntityManager.php b/lib/internal/Magento/Framework/EntityManager/EntityManager.php index 97ced3084ec03..1ec5d74cf01e0 100644 --- a/lib/internal/Magento/Framework/EntityManager/EntityManager.php +++ b/lib/internal/Magento/Framework/EntityManager/EntityManager.php @@ -1,6 +1,6 @@ getResource()->afterLoad($entity); $entity->afterLoad(); + $entity->setOrigData(); $entity->setHasDataChanges(false); } } diff --git a/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php b/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php index 9ca4a894739ae..76f70505e3abd 100644 --- a/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php +++ b/lib/internal/Magento/Framework/EntityManager/Observer/AfterEntitySave.php @@ -1,6 +1,6 @@ getEvent()->getIdentifier(); + $entity = $observer->getEvent()->getEntity(); + if ($entity instanceof AbstractModel) { + $entity->beforeLoad($identifier); + } + } +} diff --git a/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntitySave.php b/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntitySave.php index a6aa43787c399..e624729c74382 100644 --- a/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntitySave.php +++ b/lib/internal/Magento/Framework/EntityManager/Observer/BeforeEntitySave.php @@ -1,6 +1,6 @@ commit(); + } catch (DuplicateException $e) { + $connection->rollBack(); + throw new AlreadyExistsException(new Phrase('Unique constraint violation found'), $e); } catch (\Exception $e) { $connection->rollBack(); throw $e; diff --git a/lib/internal/Magento/Framework/EntityManager/Operation/Create/CreateAttributes.php b/lib/internal/Magento/Framework/EntityManager/Operation/Create/CreateAttributes.php index 1ea3d9b6b089f..69d3ac47ec268 100644 --- a/lib/internal/Magento/Framework/EntityManager/Operation/Create/CreateAttributes.php +++ b/lib/internal/Magento/Framework/EntityManager/Operation/Create/CreateAttributes.php @@ -1,6 +1,6 @@ $identifier, + 'entity' => $entity, 'arguments' => $arguments ] ); diff --git a/lib/internal/Magento/Framework/EntityManager/Operation/Read/ReadAttributes.php b/lib/internal/Magento/Framework/EntityManager/Operation/Read/ReadAttributes.php index 4604781098045..edb54d69bbad6 100644 --- a/lib/internal/Magento/Framework/EntityManager/Operation/Read/ReadAttributes.php +++ b/lib/internal/Magento/Framework/EntityManager/Operation/Read/ReadAttributes.php @@ -1,6 +1,6 @@ commit(); + } catch (DuplicateException $e) { + $connection->rollBack(); + throw new AlreadyExistsException(new Phrase('Unique constraint violation found'), $e); } catch (\Exception $e) { $connection->rollBack(); throw $e; diff --git a/lib/internal/Magento/Framework/EntityManager/Operation/Update/UpdateAttributes.php b/lib/internal/Magento/Framework/EntityManager/Operation/Update/UpdateAttributes.php index e711d34a9e5ca..2905f69444408 100644 --- a/lib/internal/Magento/Framework/EntityManager/Operation/Update/UpdateAttributes.php +++ b/lib/internal/Magento/Framework/EntityManager/Operation/Update/UpdateAttributes.php @@ -1,6 +1,6 @@ 1, - 'identified_field' => 'test_identified_field', - 'test_simple' => 'test_value', - ]; - $columns = [ - 'test_nullable' => [ - 'NULLABLE' => true, - 'DEFAULT' => false, - 'IDENTITY' => false, - 'COLUMN_NAME' => 'test_nullable', - ], - 'test_simple' => [ - 'NULLABLE' => true, - 'DEFAULT' => false, - 'IDENTITY' => false, - 'COLUMN_NAME' => 'test_simple', - ], - ]; - $preparedColumns = [ - 'test_identified_field' => null, - 'test_nullable' => null, - 'test_simple' => 'test_value', - ]; - $this->metadataPoolMock->expects($this->once()) ->method('getMetadata') ->with('test') @@ -115,7 +96,78 @@ public function testExecute() $this->metadataMock->expects($this->exactly(2)) ->method('getIdentifierField') ->willReturn('test_identified_field'); - + if (empty($data['updated_at'])) { + unset($data['updated_at']); + } $this->assertSame($data, $this->model->execute('test', $data)); } + + /** + * @return array + */ + public function columnsDataProvider() + { + $data = [ + 'test_link_field' => 1, + 'identified_field' => 'test_identified_field', + 'test_simple' => 'test_value', + ]; + $columns = [ + 'test_nullable' => [ + 'NULLABLE' => true, + 'DEFAULT' => false, + 'IDENTITY' => false, + 'COLUMN_NAME' => 'test_nullable', + ], + 'test_simple' => [ + 'NULLABLE' => true, + 'DEFAULT' => false, + 'IDENTITY' => false, + 'COLUMN_NAME' => 'test_simple', + ], + ]; + $preparedColumns = [ + 'test_identified_field' => null, + 'test_nullable' => null, + 'test_simple' => 'test_value', + ]; + + return [ + 'default' => [ + 'data' => $data, + 'columns' => $columns, + 'preparedColumns' => $preparedColumns, + ], + 'empty timestamp field' => [ + 'data' => array_merge($data, ['updated_at' => '']), + 'columns' => array_merge( + $columns, + [ + 'updated_at' => [ + 'NULLABLE' => false, + 'DEFAULT' => 'CURRENT_TIMESTAMP', + 'IDENTITY' => false, + 'COLUMN_NAME' => 'updated_at', + ], + ] + ), + 'preparedColumns' => $preparedColumns, + ], + 'filled timestamp field' => [ + 'data' => array_merge($data, ['updated_at' => '2016-01-01 00:00:00']), + 'columns' => array_merge( + $columns, + [ + 'updated_at' => [ + 'NULLABLE' => false, + 'DEFAULT' => 'CURRENT_TIMESTAMP', + 'IDENTITY' => false, + 'COLUMN_NAME' => 'updated_at', + ], + ] + ), + 'preparedColumns' => array_merge($preparedColumns, ['updated_at' => '2016-01-01 00:00:00']), + ], + ]; + } } diff --git a/lib/internal/Magento/Framework/EntityManager/Test/Unit/MapperTest.php b/lib/internal/Magento/Framework/EntityManager/Test/Unit/MapperTest.php index 498dba3f26b40..9381972f904ce 100644 --- a/lib/internal/Magento/Framework/EntityManager/Test/Unit/MapperTest.php +++ b/lib/internal/Magento/Framework/EntityManager/Test/Unit/MapperTest.php @@ -1,6 +1,6 @@ metadataPool = $this->getMockBuilder(MetadataPool::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resourceConnection = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->createMain = $this->getMockBuilder(CreateMain::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->create = (new ObjectManager($this))->getObject(Create::class, [ + 'metadataPool' => $this->metadataPool, + 'resourceConnection' => $this->resourceConnection, + 'createMain' => $this->createMain, + ]); + } + + /** + * @expectedException \Magento\Framework\Exception\AlreadyExistsException + */ + public function testDuplicateExceptionProcessingOnExecute() + { + $metadata = $this->getMock(EntityMetadataInterface::class); + $this->metadataPool->expects($this->any())->method('getMetadata')->willReturn($metadata); + + $connection = $this->getMock(AdapterInterface::class); + $connection->expects($this->once())->method('rollback'); + $this->resourceConnection->expects($this->any())->method('getConnectionByName')->willReturn($connection); + + $this->createMain->expects($this->once())->method('execute')->willThrowException(new DuplicateException()); + + $entity = $this->getMockBuilder(DataObject::class) + ->disableOriginalConstructor() + ->getMock(); + $this->create->execute($entity); + } +} diff --git a/lib/internal/Magento/Framework/EntityManager/Test/Unit/Operation/UpdateTest.php b/lib/internal/Magento/Framework/EntityManager/Test/Unit/Operation/UpdateTest.php new file mode 100644 index 0000000000000..a49eb1c902475 --- /dev/null +++ b/lib/internal/Magento/Framework/EntityManager/Test/Unit/Operation/UpdateTest.php @@ -0,0 +1,78 @@ +metadataPool = $this->getMockBuilder(MetadataPool::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resourceConnection = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->updateMain = $this->getMockBuilder(UpdateMain::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->update = (new ObjectManager($this))->getObject(Update::class, [ + 'metadataPool' => $this->metadataPool, + 'resourceConnection' => $this->resourceConnection, + 'updateMain' => $this->updateMain, + ]); + } + + /** + * @expectedException \Magento\Framework\Exception\AlreadyExistsException + */ + public function testDuplicateExceptionProcessingOnExecute() + { + $metadata = $this->getMock(EntityMetadataInterface::class); + $this->metadataPool->expects($this->any())->method('getMetadata')->willReturn($metadata); + + $connection = $this->getMock(AdapterInterface::class); + $connection->expects($this->once())->method('rollback'); + $this->resourceConnection->expects($this->any())->method('getConnectionByName')->willReturn($connection); + + $this->updateMain->expects($this->once())->method('execute')->willThrowException(new DuplicateException()); + + $entity = $this->getMockBuilder(DataObject::class) + ->disableOriginalConstructor() + ->getMock(); + $this->update->execute($entity); + } +} diff --git a/lib/internal/Magento/Framework/EntityManager/Test/Unit/TypeResolverTest.php b/lib/internal/Magento/Framework/EntityManager/Test/Unit/TypeResolverTest.php index da84e4b8901c3..d130811dbc336 100644 --- a/lib/internal/Magento/Framework/EntityManager/Test/Unit/TypeResolverTest.php +++ b/lib/internal/Magento/Framework/EntityManager/Test/Unit/TypeResolverTest.php @@ -1,6 +1,6 @@ escapeHtml($item); + $result[] = $this->escapeHtml($item, $allowedTags); } } elseif (strlen($data)) { if (is_array($allowedTags) && !empty($allowedTags)) { - $allowed = implode('|', $allowedTags); - $result = preg_replace('/<([\/\s\r\n]*)(' . $allowed . ')([\/\s\r\n]*)>/si', '##$1$2$3##', $data); - $result = htmlspecialchars($result, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', false); - $result = preg_replace('/##([\/\s\r\n]*)(' . $allowed . ')([\/\s\r\n]*)##/si', '<$1$2$3>', $result); + $notAllowedTags = array_intersect( + array_map('strtolower', $allowedTags), + $this->notAllowedTags + ); + if (!empty($notAllowedTags)) { + $this->getLogger()->critical( + 'The following tag(s) are not allowed: ' . implode(', ', $notAllowedTags) + ); + $allowedTags = array_diff($allowedTags, $this->notAllowedTags); + } + $wrapperElementId = uniqid(); + $domDocument = new \DOMDocument('1.0', 'UTF-8'); + set_error_handler( + function ($errorNumber, $errorString) { + throw new \Exception($errorString, $errorNumber); + } + ); + $string = mb_convert_encoding($data, 'HTML-ENTITIES', 'UTF-8'); + try { + $domDocument->loadHTML( + '' . $string . '' + ); + } catch (\Exception $e) { + restore_error_handler(); + $this->getLogger()->critical($e); + } + restore_error_handler(); + + $this->removeNotAllowedTags($domDocument, $allowedTags); + $this->removeNotAllowedAttributes($domDocument); + $this->escapeText($domDocument); + $this->escapeAttributeValues($domDocument); + + $result = mb_convert_encoding($domDocument->saveHTML(), 'UTF-8', 'HTML-ENTITIES'); + preg_match('/(.+)<\/body><\/html>$/si', $result, $matches); + return !empty($matches) ? $matches[1] : ''; } else { $result = htmlspecialchars($data, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', false); } @@ -44,6 +97,91 @@ public function escapeHtml($data, $allowedTags = null) return $result; } + /** + * Remove not allowed tags + * + * @param \DOMDocument $domDocument + * @param string[] $allowedTags + * @return void + */ + private function removeNotAllowedTags(\DOMDocument $domDocument, array $allowedTags) + { + $xpath = new \DOMXPath($domDocument); + $nodes = $xpath->query( + '//node()[name() != \'' + . implode('\' and name() != \'', array_merge($allowedTags, ['html', 'body'])) + . '\']' + ); + foreach ($nodes as $node) { + if ($node->nodeName != '#text' && $node->nodeName != '#comment') { + $node->parentNode->replaceChild($domDocument->createTextNode($node->textContent), $node); + } + } + } + + /** + * Remove not allowed attributes + * + * @param \DOMDocument $domDocument + * @return void + */ + private function removeNotAllowedAttributes(\DOMDocument $domDocument) + { + $xpath = new \DOMXPath($domDocument); + $nodes = $xpath->query( + '//@*[name() != \'' . implode('\' and name() != \'', $this->allowedAttributes) . '\']' + ); + foreach ($nodes as $node) { + $node->parentNode->removeAttribute($node->nodeName); + } + } + + /** + * Escape text + * + * @param \DOMDocument $domDocument + * @return void + */ + private function escapeText(\DOMDocument $domDocument) + { + $xpath = new \DOMXPath($domDocument); + $nodes = $xpath->query('//text()'); + foreach ($nodes as $node) { + $node->textContent = $this->escapeHtml($node->textContent); + } + } + + /** + * Escape attribute values + * + * @param \DOMDocument $domDocument + * @return void + */ + private function escapeAttributeValues(\DOMDocument $domDocument) + { + $xpath = new \DOMXPath($domDocument); + $nodes = $xpath->query('//@*'); + foreach ($nodes as $node) { + $value = $this->escapeAttributeValue( + $node->nodeName, + $node->parentNode->getAttribute($node->nodeName) + ); + $node->parentNode->setAttribute($node->nodeName, $value); + } + } + + /** + * Escape attribute value using escapeHtml or escapeUrl + * + * @param string $name + * @param string $value + * @return string + */ + private function escapeAttributeValue($name, $value) + { + return in_array($name, $this->escapeAsUrlAttributes) ? $this->escapeUrl($value) : $this->escapeHtml($value); + } + /** * Escape a string for the HTML attribute context * @@ -89,7 +227,22 @@ public function encodeUrlParam($string) */ public function escapeJs($string) { - return $this->getEscaper()->escapeJs($string); + if ($string === '' || ctype_digit($string)) { + return $string; + } + + return preg_replace_callback( + '/[^a-z0-9,\._]/iSu', + function ($matches) { + $chr = $matches[0]; + if (strlen($chr) != 1) { + $chr = mb_convert_encoding($chr, 'UTF-16BE', 'UTF-8'); + $chr = ($chr === false) ? '' : $chr; + } + return sprintf('\\u%04s', strtoupper(bin2hex($chr))); + }, + $string + ); } /** @@ -172,4 +325,19 @@ private function getEscaper() } return $this->escaper; } + + /** + * Get logger + * + * @return \Psr\Log\LoggerInterface + * @deprecated + */ + private function getLogger() + { + if ($this->logger == null) { + $this->logger = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Psr\Log\LoggerInterface::class); + } + return $this->logger; + } } diff --git a/lib/internal/Magento/Framework/Event.php b/lib/internal/Magento/Framework/Event.php index 275d4e0fc257d..f6958b947135b 100644 --- a/lib/internal/Magento/Framework/Event.php +++ b/lib/internal/Magento/Framework/Event.php @@ -1,6 +1,6 @@ @@ -16,4 +16,4 @@ -
    \ No newline at end of file +
    diff --git a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/event_invalid_config.xml b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/event_invalid_config.xml index d1e308cada5e3..fafe76ea5a9b2 100644 --- a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/event_invalid_config.xml +++ b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/event_invalid_config.xml @@ -1,7 +1,7 @@ @@ -10,4 +10,4 @@ -
    \ No newline at end of file +
    diff --git a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php index cabe1e141ddb8..fd950552d7fa9 100644 --- a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php +++ b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Event/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/Event/Test/Unit/ConfigTest.php index 5a7fc373bab10..7906587c1bd86 100644 --- a/lib/internal/Magento/Framework/Event/Test/Unit/ConfigTest.php +++ b/lib/internal/Magento/Framework/Event/Test/Unit/ConfigTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/EventFactory.php b/lib/internal/Magento/Framework/EventFactory.php index 7bc756b425cf6..452b8dbde546d 100644 --- a/lib/internal/Magento/Framework/EventFactory.php +++ b/lib/internal/Magento/Framework/EventFactory.php @@ -1,6 +1,6 @@ mimeTypes[$extension])) { $result = $this->mimeTypes[$extension]; } diff --git a/lib/internal/Magento/Framework/File/Size.php b/lib/internal/Magento/Framework/File/Size.php index 2ef622c7e331e..e71fa062cb258 100644 --- a/lib/internal/Magento/Framework/File/Size.php +++ b/lib/internal/Magento/Framework/File/Size.php @@ -1,6 +1,6 @@ [__DIR__ . '/_files/javascript.js', 'application/javascript'], 'weird extension' => [__DIR__ . '/_files/file.weird', 'application/octet-stream'], + 'weird uppercase extension' => [__DIR__ . '/_files/UPPERCASE.WEIRD', 'application/octet-stream'], ]; } } diff --git a/lib/internal/Magento/Framework/File/Test/Unit/Transfer/Adapter/HttpTest.php b/lib/internal/Magento/Framework/File/Test/Unit/Transfer/Adapter/HttpTest.php index 309a6b2e3559d..9f177beb696d1 100644 --- a/lib/internal/Magento/Framework/File/Test/Unit/Transfer/Adapter/HttpTest.php +++ b/lib/internal/Magento/Framework/File/Test/Unit/Transfer/Adapter/HttpTest.php @@ -1,6 +1,6 @@ create($this->driver->getParentDirectory($newPath)); } $absolutePath = $this->driver->getAbsolutePath($this->path, $path); - $absoluteNewPath = $targetDirectory->driver->getAbsolutePath($this->path, $newPath); + $absoluteNewPath = $targetDirectory->getAbsolutePath($newPath); return $this->driver->rename($absolutePath, $absoluteNewPath, $targetDirectory->driver); } @@ -144,8 +144,6 @@ public function copyFile($path, $destination, WriteInterface $targetDirectory = */ public function createSymlink($path, $destination, WriteInterface $targetDirectory = null) { - $this->assertIsFile($path); - $targetDirectory = $targetDirectory ?: $this; $parentDirectory = $this->driver->getParentDirectory($destination); if (!$targetDirectory->isExist($parentDirectory)) { diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php b/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php index e4a63dea2f846..5e3629e3d496a 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php @@ -1,6 +1,6 @@ assertInstanceOf( - \Magento\Framework\Filesystem\DriverInterface::class, + DriverInterface::class, $this->write->getDriver(), 'getDriver method expected to return instance of Magento\Framework\Filesystem\DriverInterface' ); @@ -90,8 +93,7 @@ public function testIsWritable() public function testCreateSymlinkTargetDirectoryExists() { - $targetDir = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\WriteInterface::class) - ->getMock(); + $targetDir = $this->getMockBuilder(WriteInterface::class)->getMock(); $targetDir->driver = $this->driver; $sourcePath = 'source/path/file'; $destinationDirectory = 'destination/path'; @@ -159,4 +161,66 @@ private function getAbsolutePath($path) { return $this->path . $path; } + + /** + * @param string $sourcePath + * @param string $targetPath + * @param WriteInterface $targetDir + * @dataProvider getFilePathsDataProvider + */ + public function testRenameFile($sourcePath, $targetPath, $targetDir) + { + if ($targetDir !== null) { + $targetDir->driver = $this->getMockBuilder(DriverInterface::class)->getMockForAbstractClass(); + $targetDirPath = 'TARGET_PATH/'; + $targetDir->expects($this->once()) + ->method('getAbsolutePath') + ->with($targetPath) + ->willReturn($targetDirPath . $targetPath); + $targetDir->expects($this->once()) + ->method('isExists') + ->with(dirname($targetPath)) + ->willReturn(false); + $targetDir->expects($this->once()) + ->method('create') + ->with(dirname($targetPath)); + } + + $this->driver->expects($this->any()) + ->method('getAbsolutePath') + ->willReturnMap([ + [$this->path, $sourcePath, null, $this->getAbsolutePath($sourcePath)], + [$this->path, $targetPath, null, $this->getAbsolutePath($targetPath)], + ]); + $this->driver->expects($this->any()) + ->method('isFile') + ->willReturnMap([ + [$this->getAbsolutePath($sourcePath), true], + [$this->getAbsolutePath($targetPath), true], + ]); + $this->driver->expects($this->any()) + ->method('getParentDirectory') + ->with($targetPath) + ->willReturn(dirname($targetPath)); + $this->write->renameFile($sourcePath, $targetPath, $targetDir); + } + + /** + * @return array + */ + public function getFilePathsDataProvider() + { + return [ + [ + 'path/to/source.file', + 'path/to/target.file', + null, + ], + [ + 'path/to/source.file', + 'path/to/target.file', + $this->getMockBuilder(WriteInterface::class)->getMockForAbstractClass(), + ], + ]; + } } diff --git a/lib/internal/Magento/Framework/Filesystem/Test/Unit/DirectoryListTest.php b/lib/internal/Magento/Framework/Filesystem/Test/Unit/DirectoryListTest.php index 778b8f2b3ddf5..e7fd3dba1486e 100644 --- a/lib/internal/Magento/Framework/Filesystem/Test/Unit/DirectoryListTest.php +++ b/lib/internal/Magento/Framework/Filesystem/Test/Unit/DirectoryListTest.php @@ -1,6 +1,6 @@ * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Filter; diff --git a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php index 10f1289b90c18..6639e754de21d 100644 --- a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php +++ b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php @@ -2,7 +2,7 @@ /** * Filter for removing malicious code from HTML * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -31,7 +31,7 @@ class MaliciousCode implements \Zend_Filter_Interface //js attributes '/(ondblclick|onclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onload|onunload|onerror)=[^<]*(?=\/*\>)/Uis', //tags - '/<\/?(script|meta|link|frame|iframe).*>/Uis', + '/<\/?(script|meta|link|frame|iframe|object).*>/Uis', //base64 usage '/src=[^<]*base64[^<]*(?=\/*\>)/Uis', ]; diff --git a/lib/internal/Magento/Framework/Filter/LocalizedToNormalized.php b/lib/internal/Magento/Framework/Filter/LocalizedToNormalized.php index 82685e3b332b8..cbe9e460a720f 100644 --- a/lib/internal/Magento/Framework/Filter/LocalizedToNormalized.php +++ b/lib/internal/Magento/Framework/Filter/LocalizedToNormalized.php @@ -1,6 +1,6 @@ SomeLink', 'Tag is removed SomeFrame', 'Tag is removed ', + 'Tag is removed SomeObject', ], [ 'Tag is removed SomeScript', @@ -96,6 +97,7 @@ public function filterDataProvider() 'Tag is removed SomeLink', 'Tag is removed SomeFrame', 'Tag is removed SomeIFrame', + 'Tag is removed SomeObject', ], ], 'Base64' => [ diff --git a/lib/internal/Magento/Framework/Filter/Test/Unit/InputTest.php b/lib/internal/Magento/Framework/Filter/Test/Unit/InputTest.php index 1f1d2fb18fdc5..0d83b43e4f3bc 100644 --- a/lib/internal/Magento/Framework/Filter/Test/Unit/InputTest.php +++ b/lib/internal/Magento/Framework/Filter/Test/Unit/InputTest.php @@ -1,6 +1,6 @@ json = $json ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); + $this->serialize = $serialize ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Serialize::class); + parent::__construct( + $context, + $registry, + $resource, + $resourceCollection, + $data + ); + } + /** * Init resource model * Set flag_code if it is specified in arguments @@ -68,9 +113,13 @@ public function beforeSave() public function getFlagData() { if ($this->hasFlagData()) { - return unserialize($this->getData('flag_data')); - } else { - return null; + $flagData = $this->getData('flag_data'); + $data = $this->json->unserialize($flagData); + if (JSON_ERROR_NONE == json_last_error()) { + return $data; + } else { + return $this->serialize->unserialize($flagData); + } } } @@ -82,7 +131,7 @@ public function getFlagData() */ public function setFlagData($value) { - return $this->setData('flag_data', serialize($value)); + return $this->setData('flag_data', $this->json->serialize($value)); } /** diff --git a/lib/internal/Magento/Framework/Flag/FlagResource.php b/lib/internal/Magento/Framework/Flag/FlagResource.php index 0b94b37a2fc2a..fe12e7e85d600 100644 --- a/lib/internal/Magento/Framework/Flag/FlagResource.php +++ b/lib/internal/Magento/Framework/Flag/FlagResource.php @@ -1,6 +1,6 @@ (CURLPROTO_HTTP + | CURLPROTO_HTTPS + | CURLPROTO_FTP + | CURLPROTO_FTPS + ), + 'verifypeer' => true, + 'verifyhost' => 2 + ]; /** * Curl handle @@ -41,7 +49,11 @@ class Curl implements \Zend_Http_Client_Adapter_Interface 'ssl_cert' => CURLOPT_SSLCERT, 'userpwd' => CURLOPT_USERPWD, 'useragent' => CURLOPT_USERAGENT, - 'referer' => CURLOPT_REFERER + 'referer' => CURLOPT_REFERER, + 'protocols' => CURLOPT_PROTOCOLS, + 'verifypeer' => CURLOPT_SSL_VERIFYPEER, + 'verifyhost' => CURLOPT_SSL_VERIFYHOST, + 'sslversion' => CURLOPT_SSLVERSION, ]; /** @@ -55,8 +67,6 @@ class Curl implements \Zend_Http_Client_Adapter_Interface * Apply current configuration array to transport resource * * @return \Magento\Framework\HTTP\Adapter\Curl - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ protected function _applyConfig() { @@ -65,22 +75,28 @@ protected function _applyConfig() curl_setopt($this->_getResource(), $option, $value); } - if (empty($this->_config)) { - return $this; + // apply config options + foreach ($this->getDefaultConfig() as $option => $value) { + curl_setopt($this->_getResource(), $option, $value); } - $verifyPeer = isset($this->_config['verifypeer']) ? $this->_config['verifypeer'] : true; - curl_setopt($this->_getResource(), CURLOPT_SSL_VERIFYPEER, $verifyPeer); - - $verifyHost = isset($this->_config['verifyhost']) ? $this->_config['verifyhost'] : 2; - curl_setopt($this->_getResource(), CURLOPT_SSL_VERIFYHOST, $verifyHost); + return $this; + } - foreach ($this->_config as $param => $curlOption) { + /** + * Get default options + * + * @return array + */ + private function getDefaultConfig() + { + $config = []; + foreach (array_keys($this->_config) as $param) { if (array_key_exists($param, $this->_allowedParams)) { - curl_setopt($this->_getResource(), $this->_allowedParams[$param], $this->_config[$param]); + $config[$this->_allowedParams[$param]] = $this->_config[$param]; } } - return $this; + return $config; } /** @@ -116,7 +132,9 @@ public function addOption($option, $value) */ public function setConfig($config = []) { - $this->_config = $config; + foreach ($config as $key => $value) { + $this->_config[$key] = $value; + } return $this; } @@ -160,6 +178,9 @@ public function write($method, $url, $http_ver = '1.1', $headers = [], $body = ' curl_setopt($this->_getResource(), CURLOPT_POSTFIELDS, $body); } elseif ($method == \Zend_Http_Client::GET) { curl_setopt($this->_getResource(), CURLOPT_HTTPGET, true); + } elseif ($method == \Zend_Http_Client::PUT) { + curl_setopt($this->_getResource(), CURLOPT_CUSTOMREQUEST, \Zend_Http_Client::PUT); + curl_setopt($this->_getResource(), CURLOPT_POSTFIELDS, $body); } if (is_array($headers)) { @@ -268,6 +289,13 @@ public function multiRequest($urls, $options = []) $multihandle = curl_multi_init(); + // add default parameters + foreach ($this->getDefaultConfig() as $defaultOption => $defaultValue) { + if (!isset($options[$defaultOption])) { + $options[$defaultOption] = $defaultValue; + } + } + foreach ($urls as $key => $url) { $handles[$key] = curl_init(); curl_setopt($handles[$key], CURLOPT_URL, $url); diff --git a/lib/internal/Magento/Framework/HTTP/Adapter/FileTransferFactory.php b/lib/internal/Magento/Framework/HTTP/Adapter/FileTransferFactory.php index 32a5478a45f60..2fb852910cb87 100644 --- a/lib/internal/Magento/Framework/HTTP/Adapter/FileTransferFactory.php +++ b/lib/internal/Magento/Framework/HTTP/Adapter/FileTransferFactory.php @@ -1,6 +1,6 @@ + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ class Curl implements \Magento\Framework\HTTP\ClientInterface { @@ -16,7 +17,7 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface * Max supported protocol by curl CURL_SSLVERSION_TLSv1_2 * @var int */ - private static $sslVersion = 6; + private $sslVersion; /** * Hostname @@ -86,7 +87,7 @@ class Curl implements \Magento\Framework\HTTP\ClientInterface /** * Curl - * @var object + * @var resource */ protected $_ch; @@ -117,10 +118,11 @@ public function setTimeout($value) } /** - * Constructor + * @param int|null $sslVersion */ - public function __construct() + public function __construct($sslVersion = null) { + $this->sslVersion = $sslVersion; } /** @@ -228,8 +230,11 @@ public function get($uri) /** * Make POST request * + * String type was added to parameter $param in order to support sending JSON or XML requests. + * This feature was added base on Community Pull Request https://github.com/magento/magento2/pull/8373 + * * @param string $uri - * @param array $params + * @param array|string $params * @return void * * @see \Magento\Framework\HTTP\Client#post($uri, $params) @@ -333,9 +338,13 @@ public function getStatus() /** * Make request + * + * String type was added to parameter $param in order to support sending JSON or XML requests. + * This feature was added base on Community Pull Request https://github.com/magento/magento2/pull/8373 + * * @param string $method * @param string $uri - * @param array $params + * @param array|string $params - use $params as a string in case of JSON or XML POST request. * @return void * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) @@ -346,7 +355,7 @@ protected function makeRequest($method, $uri, $params = []) $this->curlOption(CURLOPT_URL, $uri); if ($method == 'POST') { $this->curlOption(CURLOPT_POST, 1); - $this->curlOption(CURLOPT_POSTFIELDS, http_build_query($params)); + $this->curlOption(CURLOPT_POSTFIELDS, is_array($params) ? http_build_query($params) : $params); } elseif ($method == "GET") { $this->curlOption(CURLOPT_HTTPGET, 1); } else { @@ -377,10 +386,11 @@ protected function makeRequest($method, $uri, $params = []) $this->curlOption(CURLOPT_PORT, $this->_port); } - //$this->curlOption(CURLOPT_HEADER, 1); $this->curlOption(CURLOPT_RETURNTRANSFER, 1); $this->curlOption(CURLOPT_HEADERFUNCTION, [$this, 'parseHeaders']); - $this->curlOption(CURLOPT_SSLVERSION, self::$sslVersion); + if ($this->sslVersion !== null) { + $this->curlOption(CURLOPT_SSLVERSION, $this->sslVersion); + } if (count($this->_curlUserOptions)) { foreach ($this->_curlUserOptions as $k => $v) { @@ -415,6 +425,7 @@ public function doError($string) * @param resource $ch curl handle, not needed * @param string $data * @return int + * @throws \Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ protected function parseHeaders($ch, $data) @@ -422,11 +433,10 @@ protected function parseHeaders($ch, $data) if ($this->_headerCount == 0) { $line = explode(" ", trim($data), 3); if (count($line) != 3) { - return $this->doError("Invalid response line returned from server: " . $data); + $this->doError("Invalid response line returned from server: " . $data); } $this->_responseStatus = intval($line[1]); } else { - //var_dump($data); $name = $value = ''; $out = explode(": ", trim($data), 2); if (count($out) == 2) { diff --git a/lib/internal/Magento/Framework/HTTP/Client/Socket.php b/lib/internal/Magento/Framework/HTTP/Client/Socket.php index 2f6a34b06700b..75cdb61c793b3 100644 --- a/lib/internal/Magento/Framework/HTTP/Client/Socket.php +++ b/lib/internal/Magento/Framework/HTTP/Client/Socket.php @@ -1,6 +1,6 @@ ['type' => Table::TYPE_TEXT, 'size' => 255], @@ -71,11 +75,13 @@ class Base implements ActionInterface /** * @var array + * @deprecated */ protected $filterColumns; /** * @var array + * @deprecated */ protected $searchColumns; @@ -96,6 +102,7 @@ class Base implements ActionInterface /** * @var String + * @deprecated */ protected $string; @@ -106,11 +113,13 @@ class Base implements ActionInterface /** * @var array + * @deprecated */ protected $filterable = []; /** * @var array + * @deprecated */ protected $searchable = []; @@ -272,6 +281,7 @@ protected function getPrimaryFieldset() protected function createResultCollection() { $select = $this->getPrimaryResource()->getSelect(); + $select->reset(\Magento\Framework\DB\Select::COLUMNS); $select->columns($this->getPrimaryResource()->getIdFieldName()); foreach ($this->data['fieldsets'] as $fieldset) { if (isset($fieldset['references'])) { @@ -342,6 +352,8 @@ protected function prepareFields() * * @param array $field * @return void + * + * @deprecated */ protected function saveFieldByType($field) { diff --git a/lib/internal/Magento/Framework/Indexer/Action/Dummy.php b/lib/internal/Magento/Framework/Indexer/Action/Dummy.php index e0531b31bd61a..fe079b9f89794 100644 --- a/lib/internal/Magento/Framework/Indexer/Action/Dummy.php +++ b/lib/internal/Magento/Framework/Indexer/Action/Dummy.php @@ -1,6 +1,6 @@ createResultCollection() - : $this->createResultCollection()->addFieldToFilter($this->getPrimaryResource()->getRowIdFieldName(), $ids); + : $this->createResultCollection()->addFieldToFilter($this->getPrimaryResource()->getIdFieldName(), $ids); } } diff --git a/lib/internal/Magento/Framework/Indexer/ActionFactory.php b/lib/internal/Magento/Framework/Indexer/ActionFactory.php index dbd7794244ae4..cf67c059b7dcc 100644 --- a/lib/internal/Magento/Framework/Indexer/ActionFactory.php +++ b/lib/internal/Magento/Framework/Indexer/ActionFactory.php @@ -1,6 +1,6 @@ nodeName) { case 'title': - $data['title'] = $this->getTranslatedNodeValue($childNode); + $data['title'] = $childNode->nodeValue; break; case 'description': - $data['description'] = $this->getTranslatedNodeValue($childNode); + $data['description'] = $childNode->nodeValue; break; case 'saveHandler': $data['saveHandler'] = $this->getAttributeValue($childNode, 'class'); @@ -207,6 +207,7 @@ protected function convertField(\DOMElement $node, $data) * * @param \DOMNode $node * @return string + * @deprecated */ protected function getTranslatedNodeValue(\DOMNode $node) { diff --git a/lib/internal/Magento/Framework/Indexer/Config/Reader.php b/lib/internal/Magento/Framework/Indexer/Config/Reader.php index 1179c2df98d49..a3ee733d783ca 100644 --- a/lib/internal/Magento/Framework/Indexer/Config/Reader.php +++ b/lib/internal/Magento/Framework/Indexer/Config/Reader.php @@ -1,6 +1,6 @@ $documentValue) { $batch[$documentName] = $documentValue; - if (++$i >= $size) { - $items[] = $batch; + if (++$i == $size) { + yield $batch; $i = 0; $batch = []; } } if (count($batch) > 0) { - $items[] = $batch; + yield $batch; } - return $items; } } diff --git a/lib/internal/Magento/Framework/Indexer/SaveHandler/Grid.php b/lib/internal/Magento/Framework/Indexer/SaveHandler/Grid.php index ddce47a9b21d6..e183c2946662d 100644 --- a/lib/internal/Magento/Framework/Indexer/SaveHandler/Grid.php +++ b/lib/internal/Magento/Framework/Indexer/SaveHandler/Grid.php @@ -1,6 +1,6 @@ getName() . $dimension->getValue(); } } + return $this->resource->getTableName(implode('_', $tableNameParts)); } @@ -63,10 +64,12 @@ public function resolve($index, array $dimensions) */ private function getScopeId($dimension) { - if (is_numeric($dimension->getValue())) { - return $dimension->getValue(); - } else { - return $this->scopeResolver->getScope($dimension->getValue())->getId(); + $scopeId = $dimension->getValue(); + + if (!is_numeric($scopeId)) { + $scopeId = $this->scopeResolver->getScope($scopeId)->getId(); } + + return $scopeId; } } diff --git a/lib/internal/Magento/Framework/Indexer/StateInterface.php b/lib/internal/Magento/Framework/Indexer/StateInterface.php index 28c8bb52911d2..7f501aed3bc50 100644 --- a/lib/internal/Magento/Framework/Indexer/StateInterface.php +++ b/lib/internal/Magento/Framework/Indexer/StateInterface.php @@ -1,6 +1,6 @@ assertSame($expected, $this->object->getItems($items, $size)); + $data = $this->object->getItems($items, $size); + $this->assertSame($expected, iterator_to_array($data)); } /** diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/Config/ConverterTest.php b/lib/internal/Magento/Framework/Indexer/Test/Unit/Config/ConverterTest.php index be8591c3032bd..8072e17f7de70 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/Config/ConverterTest.php +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/Config/ConverterTest.php @@ -1,6 +1,6 @@ @@ -18,4 +18,4 @@ Indexer public name three Indexer public description three -
    \ No newline at end of file +
    diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_merged_two.xml b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_merged_two.xml index fc3b526f5f6a2..4e6cccae3fe2b 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_merged_two.xml +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_merged_two.xml @@ -1,7 +1,7 @@ @@ -14,4 +14,4 @@ Indexer public name three Indexer public description three -
    \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_one.xml b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_one.xml index 68b7f9a6ad3f8..7c48afc403d54 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_one.xml +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_one.xml @@ -1,7 +1,7 @@ @@ -10,4 +10,4 @@ Indexer public name one Indexer public description one - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_three.xml b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_three.xml index fc3b526f5f6a2..4e6cccae3fe2b 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_three.xml +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_three.xml @@ -1,7 +1,7 @@ @@ -14,4 +14,4 @@ Indexer public name three Indexer public description three - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_two.xml b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_two.xml index f1c73990be463..e92913cd191fc 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_two.xml +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/indexer_two.xml @@ -1,7 +1,7 @@ @@ -14,4 +14,4 @@ Indexer public name three Indexer public description three - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/invalidIndexerXmlArray.php b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/invalidIndexerXmlArray.php index c7352fdf98455..eb98346f3e88f 100644 --- a/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/invalidIndexerXmlArray.php +++ b/lib/internal/Magento/Framework/Indexer/Test/Unit/_files/invalidIndexerXmlArray.php @@ -1,6 +1,6 @@ @@ -14,4 +14,4 @@ Indexer public name Indexer public description - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd b/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd index e4a33c72fe883..f196cc1f32a2d 100644 --- a/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd +++ b/lib/internal/Magento/Framework/Indexer/etc/indexer.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd b/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd index 91887a4e4ddcb..054cbaf141b0c 100644 --- a/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd +++ b/lib/internal/Magento/Framework/Indexer/etc/indexer_merged.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php b/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php index 0c920717bdf38..701532fdd04ad 100644 --- a/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php +++ b/lib/internal/Magento/Framework/Interception/Code/Generator/Interceptor.php @@ -1,6 +1,6 @@ _omConfig = $omConfig; $this->_relations = $relations; @@ -95,10 +107,11 @@ public function __construct( $this->_cacheId = $cacheId; $this->_reader = $reader; $this->_scopeList = $scopeList; - + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(Serialize::class); $intercepted = $this->_cache->load($this->_cacheId); if ($intercepted !== false) { - $this->_intercepted = unserialize($intercepted); + $this->_intercepted = $this->serializer->unserialize($intercepted); } else { $this->initialize($this->_classDefinitions->getClasses()); } @@ -129,7 +142,7 @@ public function initialize($classDefinitions = []) foreach ($classDefinitions as $class) { $this->hasPlugins($class); } - $this->_cache->save(serialize($this->_intercepted), $this->_cacheId); + $this->_cache->save($this->serializer->serialize($this->_intercepted), $this->_cacheId); } /** diff --git a/lib/internal/Magento/Framework/Interception/ConfigInterface.php b/lib/internal/Magento/Framework/Interception/ConfigInterface.php index d3e6e4daa2ffe..e6af6296440f3 100644 --- a/lib/internal/Magento/Framework/Interception/ConfigInterface.php +++ b/lib/internal/Magento/Framework/Interception/ConfigInterface.php @@ -2,7 +2,7 @@ /** * Interception config. Tells whether plugins have been added for type. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Interception; diff --git a/lib/internal/Magento/Framework/Interception/Definition/Compiled.php b/lib/internal/Magento/Framework/Interception/Definition/Compiled.php deleted file mode 100644 index 6fbe9c99dce86..0000000000000 --- a/lib/internal/Magento/Framework/Interception/Definition/Compiled.php +++ /dev/null @@ -1,39 +0,0 @@ -_definitions = $definitions; - } - - /** - * Retrieve list of methods - * - * @param string $type - * @return string[] - */ - public function getMethodList($type) - { - return $this->_definitions[$type]; - } -} diff --git a/lib/internal/Magento/Framework/Interception/Definition/Runtime.php b/lib/internal/Magento/Framework/Interception/Definition/Runtime.php index 6da06b63bed24..b3d5fa8d04412 100644 --- a/lib/internal/Magento/Framework/Interception/Definition/Runtime.php +++ b/lib/internal/Magento/Framework/Interception/Definition/Runtime.php @@ -3,7 +3,7 @@ * \Reflection based plugin method list. Uses reflection to retrieve list of interception methods defined in plugin. * Should be only used in development mode, because it reads method list on every request which is expensive. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Interception\Definition; diff --git a/lib/internal/Magento/Framework/Interception/DefinitionInterface.php b/lib/internal/Magento/Framework/Interception/DefinitionInterface.php index 72941ba8282fa..f9fd3e2c15f57 100644 --- a/lib/internal/Magento/Framework/Interception/DefinitionInterface.php +++ b/lib/internal/Magento/Framework/Interception/DefinitionInterface.php @@ -2,7 +2,7 @@ /** * Plugin method definitions. Provide the list of interception methods in specified plugin. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Interception; diff --git a/lib/internal/Magento/Framework/Interception/Interceptor.php b/lib/internal/Magento/Framework/Interception/Interceptor.php index 9aa00e1c75175..359d8902af941 100644 --- a/lib/internal/Magento/Framework/Interception/Interceptor.php +++ b/lib/internal/Magento/Framework/Interception/Interceptor.php @@ -1,6 +1,6 @@ serializer = $serializer ?: $objectManager->get(Serialize::class); + parent::__construct($reader, $configScope, $cache, $cacheId, $this->serializer); $this->_omConfig = $omConfig; $this->_relations = $relations; $this->_definitions = $definitions; @@ -149,6 +166,7 @@ protected function _inheritPlugins($type) } $this->_inherited[$type] = null; if (is_array($plugins) && count($plugins)) { + $this->filterPlugins($plugins); uasort($plugins, [$this, '_sort']); $this->trimInstanceStartingBackslash($plugins); $this->_inherited[$type] = $plugins; @@ -269,9 +287,9 @@ protected function _loadScopedData() $cacheId = implode('|', $this->_scopePriorityScheme) . "|" . $this->_cacheId; $data = $this->_cache->load($cacheId); if ($data) { - list($this->_data, $this->_inherited, $this->_processed) = unserialize($data); - foreach ($this->_scopePriorityScheme as $scope) { - $this->_loadedScopes[$scope] = true; + list($this->_data, $this->_inherited, $this->_processed) = $this->serializer->unserialize($data); + foreach ($this->_scopePriorityScheme as $scopeCode) { + $this->_loadedScopes[$scopeCode] = true; } } else { $virtualTypes = []; @@ -279,18 +297,17 @@ protected function _loadScopedData() if (false == isset($this->_loadedScopes[$scopeCode])) { $data = $this->_reader->read($scopeCode); unset($data['preferences']); - if (!count($data)) { - continue; - } - $this->_inherited = []; - $this->_processed = []; - $this->merge($data); - $this->_loadedScopes[$scopeCode] = true; - foreach ($data as $class => $config) { - if (isset($config['type'])) { - $virtualTypes[] = $class; + if (count($data) > 0) { + $this->_inherited = []; + $this->_processed = []; + $this->merge($data); + foreach ($data as $class => $config) { + if (isset($config['type'])) { + $virtualTypes[] = $class; + } } } + $this->_loadedScopes[$scopeCode] = true; } if ($this->isCurrentScope($scopeCode)) { break; @@ -302,7 +319,10 @@ protected function _loadScopedData() foreach ($this->getClassDefinitions() as $class) { $this->_inheritPlugins($class); } - $this->_cache->save(serialize([$this->_data, $this->_inherited, $this->_processed]), $cacheId); + $this->_cache->save( + $this->serializer->serialize([$this->_data, $this->_inherited, $this->_processed]), + $cacheId + ); } $this->_pluginInstances = []; } @@ -348,4 +368,34 @@ public function merge(array $config) } } } + + /** + * Remove from list not existing plugins + * + * @param array $plugins + * @return void + */ + private function filterPlugins(array &$plugins) + { + foreach ($plugins as $name => $plugin) { + if (empty($plugin['instance'])) { + unset($plugins[$name]); + $this->getLogger()->info("Reference to undeclared plugin with name '{$name}'."); + } + } + } + + /** + * Get logger + * + * @return \Psr\Log\LoggerInterface + * @deprecated + */ + private function getLogger() + { + if ($this->logger === null) { + $this->logger = $this->_objectManager->get(\Psr\Log\LoggerInterface::class); + } + return $this->logger; + } } diff --git a/lib/internal/Magento/Framework/Interception/PluginListInterface.php b/lib/internal/Magento/Framework/Interception/PluginListInterface.php index eeb8735bf74ea..64b8549893885 100644 --- a/lib/internal/Magento/Framework/Interception/PluginListInterface.php +++ b/lib/internal/Magento/Framework/Interception/PluginListInterface.php @@ -2,7 +2,7 @@ /** * List of plugins configured in application * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Interception; diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php index 4c26b41a1547a..43ff5985ec383 100644 --- a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php +++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/Generator/InterceptorTest.php @@ -1,6 +1,6 @@ relationsMock = $this->getMockForAbstractClass( \Magento\Framework\ObjectManager\RelationsInterface::class ); + $this->serializerMock = $this->getMock(SerializerInterface::class); + $this->objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); } /** @@ -131,14 +141,22 @@ public function testHasPluginsWhenDataIsNotCached($expectedResult, $type, $entit $this->relationsMock->expects($this->any())->method('has')->will($this->returnValue($expectedResult)); $this->relationsMock->expects($this->any())->method('getParents')->will($this->returnValue($entityParents)); - $model = new \Magento\Framework\Interception\Config\Config( - $this->readerMock, - $this->configScopeMock, - $this->cacheMock, - $this->relationsMock, - $this->omConfigMock, - $this->definitionMock, - 'interception' + $this->serializerMock->expects($this->once()) + ->method('serialize'); + + $this->serializerMock->expects($this->never())->method('unserialize'); + + $model = $this->objectManagerHelper->getObject( + \Magento\Framework\Interception\Config\Config::class, + [ + 'reader' => $this->readerMock, + 'scopeList' => $this->configScopeMock, + 'cache' => $this->cacheMock, + 'relations' => $this->relationsMock, + 'omConfig' => $this->omConfigMock, + 'classDefinitions' => $this->definitionMock, + 'serializer' => $this->serializerMock, + ] ); $this->assertEquals($expectedResult, $model->hasPlugins($type)); @@ -163,18 +181,32 @@ public function testHasPluginsWhenDataIsCached($expectedResult, $type) ]; $this->readerMock->expects($this->never())->method('read'); $this->cacheMock->expects($this->never())->method('save'); + $serializedValue = 'serializedData'; $this->cacheMock->expects($this->any()) ->method('load') ->with($cacheId) - ->will($this->returnValue(serialize($interceptionData))); - $model = new \Magento\Framework\Interception\Config\Config( - $this->readerMock, - $this->configScopeMock, - $this->cacheMock, - new \Magento\Framework\ObjectManager\Relations\Runtime(), - $this->omConfigMock, - $this->definitionMock, - $cacheId + ->will($this->returnValue($serializedValue)); + + $this->serializerMock->expects($this->never())->method('serialize'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($serializedValue) + ->willReturn($interceptionData); + + $model = $this->objectManagerHelper->getObject( + \Magento\Framework\Interception\Config\Config::class, + [ + 'reader' => $this->readerMock, + 'scopeList' => $this->configScopeMock, + 'cache' => $this->cacheMock, + 'relations' => $this->objectManagerHelper->getObject( + \Magento\Framework\ObjectManager\Relations\Runtime::class + ), + 'omConfig' => $this->omConfigMock, + 'classDefinitions' => $this->definitionMock, + 'cacheId' => $cacheId, + 'serializer' => $this->serializerMock, + ] ); $this->assertEquals($expectedResult, $model->hasPlugins($type)); diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Custom/Module/Model/InterfaceValidator/Item.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Custom/Module/Model/InterfaceValidator/Item.php index 31a811611fbc5..256c495de378c 100644 --- a/lib/internal/Magento/Framework/Interception/Test/Unit/Custom/Module/Model/InterfaceValidator/Item.php +++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Custom/Module/Model/InterfaceValidator/Item.php @@ -1,6 +1,6 @@ 'definitions']; - - /** - * @covers \Magento\Framework\Interception\Definition\Compiled::getMethodList - * @covers \Magento\Framework\Interception\Definition\Compiled::__construct - */ - public function testGetMethodList() - { - $model = new \Magento\Framework\Interception\Definition\Compiled($this->_definitions); - $this->assertEquals('definitions', $model->getMethodList('type')); - } -} diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/ObjectManager/Config/DeveloperTest.php b/lib/internal/Magento/Framework/Interception/Test/Unit/ObjectManager/Config/DeveloperTest.php index 45a125252c733..3f84e0e30ff99 100644 --- a/lib/internal/Magento/Framework/Interception/Test/Unit/ObjectManager/Config/DeveloperTest.php +++ b/lib/internal/Magento/Framework/Interception/Test/Unit/ObjectManager/Config/DeveloperTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\ObjectManager\Config\Reader\Dom::class, [], [], '', false); $readerMock->expects($this->any())->method('read')->will($this->returnValueMap($readerMap)); - $this->_configScopeMock = $this->getMock(\Magento\Framework\Config\ScopeInterface::class); - $this->_cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); + $this->configScopeMock = $this->getMock(\Magento\Framework\Config\ScopeInterface::class); + $this->cacheMock = $this->getMock(\Magento\Framework\Config\CacheInterface::class); // turn cache off - $this->_cacheMock->expects($this->any()) + $this->cacheMock->expects($this->any()) ->method('get') ->will($this->returnValue(false)); @@ -59,62 +72,76 @@ protected function setUp() $omConfigMock->expects($this->any())->method('getOriginalInstanceType')->will($this->returnArgument(0)); - $this->_objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); - $this->_objectManagerMock->expects($this->any())->method('get')->will($this->returnArgument(0)); + $this->objectManagerMock = $this->getMock(ObjectManagerInterface::class); + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnArgument(0); + $this->serializerMock = $this->getMock(SerializerInterface::class); $definitions = new \Magento\Framework\ObjectManager\Definition\Runtime(); - $this->_model = new \Magento\Framework\Interception\PluginList\PluginList( - $readerMock, - $this->_configScopeMock, - $this->_cacheMock, - new \Magento\Framework\ObjectManager\Relations\Runtime(), - $omConfigMock, - new \Magento\Framework\Interception\Definition\Runtime(), - $this->_objectManagerMock, - $definitions, - ['global'], - 'interception' + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->object = $objectManagerHelper->getObject( + \Magento\Framework\Interception\PluginList\PluginList::class, + [ + 'reader' => $readerMock, + 'configScope' => $this->configScopeMock, + 'cache' => $this->cacheMock, + 'relations' => new \Magento\Framework\ObjectManager\Relations\Runtime(), + 'omConfig' => $omConfigMock, + 'definitions' => new \Magento\Framework\Interception\Definition\Runtime(), + 'objectManager' => $this->objectManagerMock, + 'classDefinitions' => $definitions, + 'scopePriorityScheme' => ['global'], + 'cacheId' => 'interception', + 'serializer' => $this->serializerMock + ] + ); + + $this->loggerMock = $this->getMock(\Psr\Log\LoggerInterface::class); + $objectManagerHelper->setBackwardCompatibleProperty( + $this->object, + 'logger', + $this->loggerMock ); } public function testGetPlugin() { - $this->_configScopeMock->expects($this->any())->method('getCurrentScope')->will($this->returnValue('backend')); - $this->_model->getNext(\Magento\Framework\Interception\Test\Unit\Custom\Module\Model\Item::class, 'getName'); - $this->_model->getNext( + $this->configScopeMock->expects($this->any())->method('getCurrentScope')->will($this->returnValue('backend')); + $this->object->getNext(\Magento\Framework\Interception\Test\Unit\Custom\Module\Model\Item::class, 'getName'); + $this->object->getNext( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\ItemContainer::class, 'getName' ); - $this->_model->getNext( + $this->object->getNext( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\StartingBackslash::class, 'getName' ); - $this->assertEquals( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\ItemPlugin\Simple::class, - $this->_model->getPlugin( + $this->object->getPlugin( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\Item::class, 'simple_plugin' ) ); $this->assertEquals( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\ItemPlugin\Advanced::class, - $this->_model->getPlugin( + $this->object->getPlugin( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\Item::class, 'advanced_plugin' ) ); $this->assertEquals( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\ItemContainerPlugin\Simple::class, - $this->_model->getPlugin( + $this->object->getPlugin( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\ItemContainer::class, 'simple_plugin' ) ); $this->assertEquals( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\StartingBackslash\Plugin::class, - $this->_model->getPlugin( + $this->object->getPlugin( \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\StartingBackslash::class, 'simple_plugin' ) @@ -131,14 +158,14 @@ public function testGetPlugin() */ public function testGetPlugins($expectedResult, $type, $method, $scopeCode, $code = '__self') { - $this->_configScopeMock->expects( + $this->configScopeMock->expects( $this->any() )->method( 'getCurrentScope' )->will( $this->returnValue($scopeCode) ); - $this->assertEquals($expectedResult, $this->_model->getNext($type, $method, $code)); + $this->assertEquals($expectedResult, $this->object->getNext($type, $method, $code)); } /** @@ -206,11 +233,42 @@ public function getPluginsDataProvider() */ public function testInheritPluginsWithNonExistingClass() { - $this->_configScopeMock->expects($this->any()) + $this->configScopeMock->expects($this->any()) ->method('getCurrentScope') ->will($this->returnValue('frontend')); - $this->_model->getNext('SomeType', 'someMethod'); + $this->object->getNext('SomeType', 'someMethod'); + } + + public function testLoadScopedDataNotCached() + { + $this->configScopeMock->expects($this->exactly(3)) + ->method('getCurrentScope') + ->will($this->returnValue('scope')); + $this->serializerMock->expects($this->once()) + ->method('serialize'); + $this->serializerMock->expects($this->never()) + ->method('unserialize'); + $this->cacheMock->expects($this->once()) + ->method('save'); + + $this->assertEquals(null, $this->object->getNext('Type', 'method')); + } + + /** + * @covers \Magento\Framework\Interception\PluginList\PluginList::getNext + * @covers \Magento\Framework\Interception\PluginList\PluginList::_inheritPlugins + */ + public function testInheritPluginsWithNotExistingPlugin() + { + $this->loggerMock->expects($this->once()) + ->method('info') + ->with("Reference to undeclared plugin with name 'simple_plugin'."); + $this->configScopeMock->expects($this->any()) + ->method('getCurrentScope') + ->will($this->returnValue('frontend')); + + $this->assertNull($this->object->getNext('typeWithoutInstance', 'someMethod')); } /** @@ -219,17 +277,52 @@ public function testInheritPluginsWithNonExistingClass() */ public function testLoadScopedDataCached() { - $this->_configScopeMock->expects($this->once()) + $this->configScopeMock->expects($this->once()) ->method('getCurrentScope') ->will($this->returnValue('scope')); $data = [['key'], ['key'], ['key']]; + $serializedData = 'serialized data'; - $this->_cacheMock->expects($this->once()) + $this->serializerMock->expects($this->never()) + ->method('serialize'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn($data); + $this->cacheMock->expects($this->once()) ->method('load') ->with('global|scope|interception') - ->will($this->returnValue(serialize($data))); + ->willReturn($serializedData); + + $this->assertEquals(null, $this->object->getNext('Type', 'method')); + } + + /** + * @covers \Magento\Framework\Interception\PluginList\PluginList::getNext + * @covers \Magento\Framework\Interception\PluginList\PluginList::_loadScopedData + */ + public function testLoadScopeDataWithEmptyData() + { + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->will($this->returnArgument(0)); + $this->configScopeMock->expects($this->any()) + ->method('getCurrentScope') + ->will($this->returnValue('emptyscope')); - $this->assertEquals(null, $this->_model->getNext('Type', 'method')); + $this->assertEquals( + [4 => ['simple_plugin']], + $this->object->getNext( + \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\Item::class, + 'getName' + ) + ); + $this->assertEquals( + \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\ItemPlugin\Simple::class, + $this->object->getPlugin( + \Magento\Framework\Interception\Test\Unit\Custom\Module\Model\Item::class, + 'simple_plugin' + ) + ); } } diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php b/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php index 832a5a67599da..faca7a24bfff8 100644 --- a/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php +++ b/lib/internal/Magento/Framework/Interception/Test/Unit/_files/reader_mock_map.php @@ -1,6 +1,6 @@ 'NonExistingPluginClass', ], ], + ], + 'typeWithoutInstance' => [ + 'plugins' => [ + 'simple_plugin' => [], + ], ] ] + ], + [ + 'emptyscope', + [ + + ] ] ]; diff --git a/lib/internal/Magento/Framework/Intl/DateTimeFactory.php b/lib/internal/Magento/Framework/Intl/DateTimeFactory.php index 6d45f9503d005..87d27b1d085ed 100644 --- a/lib/internal/Magento/Framework/Intl/DateTimeFactory.php +++ b/lib/internal/Magento/Framework/Intl/DateTimeFactory.php @@ -1,6 +1,6 @@ _data[self::CUSTOM_ATTRIBUTES][$key]) + ? $this->_data[self::CUSTOM_ATTRIBUTES][$key] + : null; if ($data instanceof \Magento\Framework\Api\AttributeValue) { $data = $data->getValue(); } + if (null !== $index && isset($data[$index])) { + return $data[$index]; + } } } + return $data; } diff --git a/lib/internal/Magento/Framework/Model/AbstractModel.php b/lib/internal/Magento/Framework/Model/AbstractModel.php index dbbb20021b9f4..67db6a10c40db 100644 --- a/lib/internal/Magento/Framework/Model/AbstractModel.php +++ b/lib/internal/Magento/Framework/Model/AbstractModel.php @@ -1,6 +1,6 @@ _beforeLoad($modelId, $field); $this->_getResource()->load($this, $modelId, $field); - $this->_afterLoad(); - $this->setOrigData(); - $this->_hasDataChanges = false; - $this->updateStoredData(); return $this; } @@ -577,6 +572,18 @@ protected function _afterLoad() return $this; } + /** + * Process operation before object load + * + * @param string $identifier + * @param string|null $field + * @return void + */ + public function beforeLoad($identifier, $field = null) + { + $this->_beforeLoad($identifier, $field); + } + /** * Object after load processing. Implemented as public interface for supporting objects after load in collections * @@ -584,7 +591,6 @@ protected function _afterLoad() */ public function afterLoad() { - $this->getResource()->afterLoad($this); $this->_afterLoad(); $this->updateStoredData(); return $this; diff --git a/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction.php b/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction.php index 2e207fde345e7..bbc9abe22efc1 100644 --- a/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction.php +++ b/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction.php @@ -2,7 +2,7 @@ /** * Action validator, remove action * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction/Allowed.php b/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction/Allowed.php index a956f99217e6e..dee1df394e2ea 100644 --- a/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction/Allowed.php +++ b/lib/internal/Magento/Framework/Model/ActionValidator/RemoveAction/Allowed.php @@ -2,7 +2,7 @@ /** * Action validator for remove action * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Model\ActionValidator\RemoveAction; diff --git a/lib/internal/Magento/Framework/Model/CallbackPool.php b/lib/internal/Magento/Framework/Model/CallbackPool.php index cf4fee33e276b..12b3e05927ac7 100644 --- a/lib/internal/Magento/Framework/Model/CallbackPool.php +++ b/lib/internal/Magento/Framework/Model/CallbackPool.php @@ -1,6 +1,6 @@ unsetData($field); } else { - $object->setData($field, serialize($value ?: $defaultValue)); + $object->setData($field, $this->getSerializer()->serialize($value ?: $defaultValue)); } return $this; @@ -132,13 +139,7 @@ protected function _serializeField(DataObject $object, $field, $defaultValue = n */ protected function _unserializeField(DataObject $object, $field, $defaultValue = null) { - $value = $object->getData($field); - - if ($value) { - $unserializedValue = @unserialize($value); - $value = $unserializedValue !== false || $value === 'b:0;' ? $unserializedValue : $value; - } - + $value = $this->getSerializer()->unserialize($object->getData($field)); if (empty($value)) { $object->setData($field, $defaultValue); } else { @@ -228,4 +229,18 @@ protected function _getColumnsForEntityLoad(\Magento\Framework\Model\AbstractMod } return $columns; } + + /** + * Get serializer + * + * @return Json + * @deprecated + */ + protected function getSerializer() + { + if (null === $this->serializer) { + $this->serializer = ObjectManager::getInstance()->get(Json::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php index fc189473505ab..22ddc6bee445d 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/AbstractDb.php @@ -1,18 +1,20 @@ transactionManager = $context->getTransactionManager(); $this->_resources = $context->getResources(); $this->objectRelationProcessor = $context->getObjectRelationProcessor(); @@ -332,6 +336,7 @@ public function getConnection() */ public function load(\Magento\Framework\Model\AbstractModel $object, $value, $field = null) { + $object->beforeLoad($value, $field); if ($field === null) { $field = $this->getIdFieldName(); } @@ -348,7 +353,10 @@ public function load(\Magento\Framework\Model\AbstractModel $object, $value, $fi $this->unserializeFields($object); $this->_afterLoad($object); - + $object->afterLoad(); + $object->setOrigData(); + $object->setHasDataChanges(false); + return $this; } @@ -375,6 +383,7 @@ protected function _getLoadSelect($field, $value, $object) * @return $this * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @throws \Exception + * @throws AlreadyExistsException * @api */ public function save(\Magento\Framework\Model\AbstractModel $object) @@ -409,6 +418,10 @@ public function save(\Magento\Framework\Model\AbstractModel $object) } $this->addCommitCallback([$object, 'afterCommitCallback'])->commit(); $object->setHasDataChanges(false); + } catch (DuplicateException $e) { + $this->rollBack(); + $object->setHasDataChanges(true); + throw new AlreadyExistsException(new Phrase('Unique constraint violation found'), $e); } catch (\Exception $e) { $this->rollBack(); $object->setHasDataChanges(true); diff --git a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php index 6c82dafb6c44e..79cd8d4be318c 100644 --- a/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php +++ b/lib/internal/Magento/Framework/Model/ResourceModel/Db/Collection/AbstractCollection.php @@ -1,6 +1,6 @@ _serializeField($dataObject, $field, $defaultValue, $unsetEmpty); + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->serializerMock = $this->getMock(Json::class); + $this->abstractResource = $objectManager->getObject(AbstractResourceStub::class); + $objectManager->setBackwardCompatibleProperty( + $this->abstractResource, + 'serializer', + $this->serializerMock + ); + } - static::assertEquals($expectation, $dataObject->getDataByKey($field)); + /** + * @param array $arguments + * @param string $expected + * @param array|string|int $serializeCalledWith + * @param int $numSerializeCalled + * @dataProvider serializeFieldsDataProvider + */ + public function testSerializeFields( + array $arguments, + $expected, + $serializeCalledWith, + $numSerializeCalled = 1 + ) { + /** @var DataObject $dataObject */ + list($dataObject, $field, $defaultValue, $unsetEmpty) = $arguments; + $this->serializerMock->expects($this->exactly($numSerializeCalled)) + ->method('serialize') + ->with($serializeCalledWith) + ->willReturn($expected); + $this->abstractResource->_serializeField($dataObject, $field, $defaultValue, $unsetEmpty); + $this->assertEquals($expected, $dataObject->getData($field)); } /** * @return array */ - public function serializableFieldsDataProvider() + public function serializeFieldsDataProvider() { + $array = ['a', 'b', 'c']; + $string = 'i am string'; + $integer = 969; + $empty = ''; $dataObject = new DataObject( [ - 'object' => new \stdClass(), - 'array' => ['a', 'b', 'c'], - 'string' => 'i am string', - 'int' => 969, - 'serialized_object' => 'O:8:"stdClass":0:{}', - 'empty_value' => '', - 'empty_value_with_default' => '' + 'array' => $array, + 'string' => $string, + 'integer' => $integer, + 'empty' => $empty, + 'empty_with_default' => '' ] ); - return [ - [[$dataObject, 'object', null, false], serialize($dataObject->getDataByKey('object'))], - [[$dataObject, 'array', null, false], serialize($dataObject->getDataByKey('array'))], - [[$dataObject, 'string', null, false], serialize($dataObject->getDataByKey('string'))], - [[$dataObject, 'int', null, false], serialize($dataObject->getDataByKey('int'))], [ - [$dataObject, 'serialized_object', null, false], - serialize($dataObject->getDataByKey('serialized_object')) + [$dataObject, 'array', null, false], + '["a","b","c"]', + $array + ], + [ + [$dataObject, 'string', null, false], + '"i am string"', + $string + ], + [ + [$dataObject, 'integer', null, false], + '969', + $integer + ], + [ + [$dataObject, 'empty', null, true], + null, + $empty, + 0 ], - [[$dataObject, 'empty_value', null, true], null], - [[$dataObject, 'empty_value_with_default', new \stdClass(), false], 'O:8:"stdClass":0:{}'], + [ + [$dataObject, 'empty_with_default', 'default', false], + '"default"', + 'default' + ] ]; } /** * @param array $arguments - * @param mixed $expectation - * @dataProvider unserializableFieldsDataProvider + * @param array|string|int|boolean $expected + * @dataProvider unserializeFieldsDataProvider */ - public function testUnserializeFields(array $arguments, $expectation) + public function testUnserializeFields(array $arguments, $expected) { /** @var DataObject $dataObject */ list($dataObject, $field, $defaultValue) = $arguments; - - $abstractResource = new AbstractResourceStub(); - - $abstractResource->_unserializeField($dataObject, $field, $defaultValue); - - static::assertEquals($expectation, $dataObject->getDataByKey($field)); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($dataObject->getData($field)) + ->willReturn($expected); + $this->abstractResource->_unserializeField($dataObject, $field, $defaultValue); + $this->assertEquals($expected, $dataObject->getData($field)); } /** * @return array */ - public function unserializableFieldsDataProvider() + public function unserializeFieldsDataProvider() { $dataObject = new DataObject( [ - 'object' => serialize(new \stdClass()), - 'array' => serialize(['a', 'b', 'c']), - 'string' => serialize('i am string'), - 'int' => serialize(969), - 'serialized_object' => serialize('O:8:"stdClass":0:{}'), - 'empty_value_with_default' => serialize(''), + 'array' => '["a","b","c"]', + 'string' => '"i am string"', + 'integer' => '969', + 'empty_with_default' => '""', 'not_serialized_string' => 'i am string', - 'serialized_boolean_false' => serialize(false) + 'serialized_boolean_false' => 'false' ] ); - - $defaultValue = new \stdClass(); - return [ - [[$dataObject, 'object', null], unserialize($dataObject->getDataByKey('object'))], - [[$dataObject, 'array', null], unserialize($dataObject->getDataByKey('array'))], - [[$dataObject, 'string', null], unserialize($dataObject->getDataByKey('string'))], - [[$dataObject, 'int', null], unserialize($dataObject->getDataByKey('int'))], - [[$dataObject, 'serialized_object', null], unserialize($dataObject->getDataByKey('serialized_object'))], - [[$dataObject, 'empty_value_with_default', $defaultValue], $defaultValue], - [[$dataObject, 'not_serialized_string', null], 'i am string'], - [[$dataObject, 'serialized_boolean_false', null], false] + [ + [$dataObject, 'array', null], + ['a', 'b', 'c'] + ], + [ + [$dataObject, 'string', null], + 'i am string' + ], + [ + [$dataObject, 'integer', null], + 969 + ], + [ + [$dataObject, 'empty_with_default', 'default', false], + 'default' + ], + [ + [$dataObject, 'not_serialized_string', null], + 'i am string' + ], + [ + [$dataObject, 'serialized_boolean_false', null], + false, + ] ]; } @@ -116,32 +174,31 @@ public function testCommitZeroLevel() ->disableOriginalConstructor() ->getMock(); - $abstractResource = new AbstractResourceStub(); - $abstractResource->setConnection($connection); - $abstractResource->addCommitCallback( + $this->abstractResource->setConnection($connection); + $this->abstractResource->addCommitCallback( function () use ($closureExpectation) { $closureExpectation->setData(1); } ); - $abstractResource->addCommitCallback( + $this->abstractResource->addCommitCallback( function () use ($closureExpectation) { $closureExpectation->getData(); } ); - $connection->expects(static::once()) + $connection->expects($this->once()) ->method('commit'); - $connection->expects(static::once()) + $connection->expects($this->once()) ->method('getTransactionLevel') ->willReturn(0); - $closureExpectation->expects(static::once()) + $closureExpectation->expects($this->once()) ->method('setData') ->with(1); - $closureExpectation->expects(static::once()) + $closureExpectation->expects($this->once()) ->method('getData'); - $abstractResource->commit(); + $this->abstractResource->commit(); } /** @@ -152,23 +209,22 @@ public function testCommitZeroLevelCallbackException() /** @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject $connection */ $connection = $this->getMock(AdapterInterface::class); - $abstractResource = new AbstractResourceStub(); - $abstractResource->setConnection($connection); - $abstractResource->addCommitCallback( + $this->abstractResource->setConnection($connection); + $this->abstractResource->addCommitCallback( function () { throw new \Exception(); } ); - $connection->expects(static::once()) + $connection->expects($this->once()) ->method('commit'); - $connection->expects(static::once()) + $connection->expects($this->once()) ->method('getTransactionLevel') ->willReturn(0); - $abstractResource->commit(); + $this->abstractResource->commit(); } - + public function testCommitNotCompletedTransaction() { /** @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject $connection */ @@ -178,24 +234,23 @@ public function testCommitNotCompletedTransaction() ->disableOriginalConstructor() ->getMock(); - $abstractResource = new AbstractResourceStub(); - $abstractResource->setConnection($connection); - $abstractResource->addCommitCallback( + $this->abstractResource->setConnection($connection); + $this->abstractResource->addCommitCallback( function () use ($closureExpectation) { $closureExpectation->setData(1); } ); - $connection->expects(static::once()) + $connection->expects($this->once()) ->method('commit'); - $connection->expects(static::once()) + $connection->expects($this->once()) ->method('getTransactionLevel') ->willReturn(1); - $closureExpectation->expects(static::never()) + $closureExpectation->expects($this->never()) ->method('setData') ->with(1); - $abstractResource->commit(); + $this->abstractResource->commit(); } } diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php index 1dcb84d276840..a6f3add797d16 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/AbstractDbTest.php @@ -1,12 +1,16 @@ willReturn($this->transactionManagerMock); $this->_model = $this->getMockForAbstractClass( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, [$contextMock], '', true, @@ -116,7 +120,7 @@ public function addUniqueFieldDataProvider() public function testAddUniqueFieldArray() { $this->assertInstanceOf( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, $this->_model->addUniqueField(['someField']) ); } @@ -134,7 +138,7 @@ public function testGetIdFieldname() { $data = 'MainTableName'; $idFieldNameProperty = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, '_idFieldName' + AbstractDb::class, '_idFieldName' ); $idFieldNameProperty->setAccessible(true); $idFieldNameProperty->setValue($this->_model, $data); @@ -158,7 +162,7 @@ public function testGetMainTableException() public function testGetMainTable($tableName, $expectedResult) { $mainTableProperty = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_mainTable' ); $mainTableProperty->setAccessible(true); @@ -195,7 +199,7 @@ public function testGetTable() $this->returnValue('tableName') ); $tablesProperty = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_tables' ); $tablesProperty->setAccessible(true); @@ -215,7 +219,7 @@ public function testGetChecksumNegative() */ public function testGetChecksum($checksum, $expected) { - $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class, [], [], '', false); + $connectionMock = $this->getMock(AdapterInterface::class, [], [], '', false); $connectionMock->expects($this->once())->method('getTablesChecksum')->with($checksum)->will( $this->returnValue([$checksum => 'checksum']) ); @@ -242,7 +246,7 @@ public function getChecksumProvider() public function testResetUniqueField() { $uniqueFields = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_uniqueFields' ); $uniqueFields->setAccessible(true); @@ -254,7 +258,7 @@ public function testResetUniqueField() public function testGetUniqueFields() { $uniqueFieldsReflection = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_uniqueFields' ); $uniqueFieldsReflection->setAccessible(true); @@ -269,36 +273,26 @@ public function testGetValidationRulesBeforeSave() public function testLoad() { - $contextMock = $this->getMock(\Magento\Framework\Model\Context::class, [], [], '', false); - $registryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); - $abstractModelMock = $this->getMockForAbstractClass( - \Magento\Framework\Model\AbstractModel::class, - [$contextMock, $registryMock], - '', - false, - true, - true, - ['__wakeup'] - ); - - $value = 'some_value'; - $idFieldName = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, - '_idFieldName' - ); - $idFieldName->setAccessible(true); - $idFieldName->setValue($this->_model, 'field_value'); - + /** @var \Magento\Framework\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject $object */ + $object = $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) + ->disableOriginalConstructor() + ->getMock(); + $object->expects($this->once())->method('beforeLoad')->with('some_value', 'field_name'); + $object->expects($this->once())->method('afterLoad')->willReturnSelf(); + $object->expects($this->once())->method('setOrigData')->willReturnSelf(); + $object->expects($this->once())->method('setHasDataChanges')->with(false)->willReturnSelf(); + $result = $this->_model->load($object, 'some_value', 'field_name'); + $this->assertEquals($this->_model, $result); $this->assertInstanceOf( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, - $this->_model->load($abstractModelMock, $value, $idFieldName) + $result ); } public function testDelete() { $connectionInterfaceMock = $this->getMock( - \Magento\Framework\DB\Adapter\AdapterInterface::class, + AdapterInterface::class, [], [], '', @@ -307,7 +301,7 @@ public function testDelete() $contextMock = $this->getMock(\Magento\Framework\Model\Context::class, [], [], '', false); $registryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); $abstractModelMock = $this->getMockForAbstractClass( - \Magento\Framework\Model\AbstractModel::class, + AbstractModel::class, [$contextMock, $registryMock], '', false, @@ -321,7 +315,7 @@ public function testDelete() ); $abstractModelMock->expects($this->once())->method('getData')->willReturn(['data' => 'value']); - $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class); + $connectionMock = $this->getMock(AdapterInterface::class); $this->transactionManagerMock->expects($this->once()) ->method('start') ->with($connectionInterfaceMock) @@ -344,13 +338,13 @@ public function testDelete() $this->returnValue('tableName') ); $mainTableReflection = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_mainTable' ); $mainTableReflection->setAccessible(true); $mainTableReflection->setValue($this->_model, 'tableName'); $idFieldNameReflection = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_idFieldName' ); $idFieldNameReflection->setAccessible(true); @@ -361,7 +355,7 @@ public function testDelete() $abstractModelMock->expects($this->once())->method('afterDelete'); $abstractModelMock->expects($this->once())->method('afterDeleteCommit'); $this->assertInstanceOf( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, $this->_model->delete($abstractModelMock) ); } @@ -371,7 +365,7 @@ public function testHasDataChangedNegative() $contextMock = $this->getMock(\Magento\Framework\Model\Context::class, [], [], '', false); $registryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); $abstractModelMock = $this->getMockForAbstractClass( - \Magento\Framework\Model\AbstractModel::class, + AbstractModel::class, [$contextMock, $registryMock], '', false, @@ -391,7 +385,7 @@ public function testHasDataChangedNegative() public function testGetDataChanged($getOriginData, $expected) { $connectionInterfaceMock = $this->getMock( - \Magento\Framework\DB\Adapter\AdapterInterface::class, + AdapterInterface::class, [], [], '', @@ -403,7 +397,7 @@ public function testGetDataChanged($getOriginData, $expected) $contextMock = $this->getMock(\Magento\Framework\Model\Context::class, [], [], '', false); $registryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); $abstractModelMock = $this->getMockForAbstractClass( - \Magento\Framework\Model\AbstractModel::class, + AbstractModel::class, [$contextMock, $registryMock], '', false, @@ -412,7 +406,7 @@ public function testGetDataChanged($getOriginData, $expected) ['__wakeup', 'getOrigData', 'getData'] ); $mainTableProperty = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_mainTable' ); $mainTableProperty->setAccessible(true); @@ -441,13 +435,13 @@ public function hasDataChangedDataProvider() public function testPrepareDataForUpdate() { - $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class, [], [], '', false); + $connectionMock = $this->getMock(AdapterInterface::class, [], [], '', false); $context = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject( \Magento\Framework\Model\Context::class ); $registryMock = $this->getMock(\Magento\Framework\Registry::class, [], [], '', false); $resourceMock = $this->getMock( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, [ '_construct', 'getConnection', @@ -459,7 +453,7 @@ public function testPrepareDataForUpdate() false ); $connectionInterfaceMock = $this->getMock( - \Magento\Framework\DB\Adapter\AdapterInterface::class, + AdapterInterface::class, [], [], '', @@ -472,7 +466,7 @@ public function testPrepareDataForUpdate() ->disableOriginalConstructor() ->getMockForAbstractClass(); $abstractModelMock = $this->getMockForAbstractClass( - \Magento\Framework\Model\AbstractModel::class, + AbstractModel::class, [$context, $registryMock, $resourceMock, $resourceCollectionMock] ); $data = 'tableName'; @@ -484,20 +478,19 @@ public function testPrepareDataForUpdate() $this->returnValue('tableName') ); $mainTableReflection = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_mainTable' ); $mainTableReflection->setAccessible(true); $mainTableReflection->setValue($this->_model, 'tableName'); $idFieldNameReflection = new \ReflectionProperty( - \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, + AbstractDb::class, '_idFieldName' ); $idFieldNameReflection->setAccessible(true); $idFieldNameReflection->setValue($this->_model, 'idFieldName'); $connectionMock->expects($this->any())->method('save')->with('tableName', 'idFieldName'); $connectionMock->expects($this->any())->method('quoteInto')->will($this->returnValue('idFieldName')); - $abstractModelMock->setIdFieldName('id'); $abstractModelMock->setData( [ @@ -551,7 +544,7 @@ public function testSaveNewObject($pkIncrement) /** * Mock SUT so as not to test extraneous logic */ - $model = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) + $model = $this->getMockBuilder(AbstractDb::class) ->disableOriginalConstructor() ->setMethods(['_prepareDataForSave', 'getIdFieldName', 'getConnection', 'getMainTable']) ->getMockForAbstractClass(); @@ -568,7 +561,7 @@ public function testSaveNewObject($pkIncrement) $reflectionProperty->setValue($model, $pkIncrement); // Mocked behavior - $connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + $connectionMock = $this->getMockBuilder(AdapterInterface::class) ->disableOriginalConstructor() ->setMethods(['lastInsertId']) ->getMockForAbstractClass(); @@ -590,7 +583,7 @@ public function testSaveNewObject($pkIncrement) // Only set object id if not PK autoincrement $setIdInvokedCount = $pkIncrement ? 1 : 0; - $inputObject = $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) + $inputObject = $this->getMockBuilder(AbstractModel::class) ->disableOriginalConstructor() ->getMock(); $inputObject->expects($this->exactly($setIdInvokedCount))->method('setId'); @@ -602,9 +595,37 @@ public function testSaveNewObject($pkIncrement) $reflectionMethod->invokeArgs($model, [$inputObject]); } + /** + * @return array + */ public function saveNewObjectDataProvider() { return [[true], [false]]; } + /** + * @expectedException \Magento\Framework\Exception\AlreadyExistsException + */ + public function testDuplicateExceptionProcessingOnSave() + { + $connection = $this->getMock(AdapterInterface::class); + $connection->expects($this->once())->method('rollback'); + + /** @var AbstractDb|\PHPUnit_Framework_MockObject_MockObject $model */ + $model = $this->getMockBuilder(AbstractDb::class) + ->disableOriginalConstructor() + ->setMethods(['getConnection']) + ->getMockForAbstractClass(); + $model->expects($this->any())->method('getConnection')->willReturn($connection); + + /** @var AbstractModel|\PHPUnit_Framework_MockObject_MockObject $object */ + $object = $this->getMockBuilder(AbstractModel::class) + ->disableOriginalConstructor() + ->getMock(); + $object->expects($this->once())->method('hasDataChanges')->willReturn(true); + $object->expects($this->once())->method('beforeSave')->willThrowException(new DuplicateException()); + $object->expects($this->once())->method('setHasDataChanges')->with(true); + + $model->save($object); + } } diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php index d458810732b6b..51fbd2ba00290 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/ResourceModel/Db/Collection/AbstractCollectionTest.php @@ -1,6 +1,6 @@ fileIteratorFactory->create($this->getFiles($filename, Dir::MODULE_ETC_DIR)); + return $this->getFilesIterator($filename, Dir::MODULE_ETC_DIR); } /** - * Go through all modules and find composer.json files of active modules + * Go through all modules and find composer.json files of active modules. * * @return FileIterator */ public function getComposerJsonFiles() { - return $this->fileIteratorFactory->create($this->getFiles('composer.json')); + return $this->getFilesIterator('composer.json'); + } + + /** + * Retrieve iterator for files with $filename from components located in component $subDir. + * + * @param string $filename + * @param string $subDir + * + * @return FileIterator + */ + private function getFilesIterator($filename, $subDir = '') + { + if (!isset($this->fileIterators[$subDir][$filename])) { + $this->fileIterators[$subDir][$filename] = $this->fileIteratorFactory->create( + $this->getFiles($filename, $subDir) + ); + } + return $this->fileIterators[$subDir][$filename]; } /** @@ -96,9 +121,9 @@ private function getFiles($filename, $subDir = '') { $result = []; foreach ($this->modulesList->getNames() as $moduleName) { - $moduleEtcDir = $this->getModuleDir($subDir, $moduleName); - $file = $moduleEtcDir . '/' . $filename; - $directoryRead = $this->readFactory->create($moduleEtcDir); + $moduleSubDir = $this->getModuleDir($subDir, $moduleName); + $file = $moduleSubDir . '/' . $filename; + $directoryRead = $this->readFactory->create($moduleSubDir); $path = $directoryRead->getRelativePath($file); if ($directoryRead->isExist($path)) { $result[] = $file; @@ -159,5 +184,6 @@ public function getModuleDir($type, $moduleName) public function setModuleDir($moduleName, $type, $path) { $this->customModuleDirs[$moduleName][$type] = $path; + $this->fileIterators = []; } } diff --git a/lib/internal/Magento/Framework/Module/Dir/ReverseResolver.php b/lib/internal/Magento/Framework/Module/Dir/ReverseResolver.php index 0db2b9cddade5..98991b589c599 100644 --- a/lib/internal/Magento/Framework/Module/Dir/ReverseResolver.php +++ b/lib/internal/Magento/Framework/Module/Dir/ReverseResolver.php @@ -2,7 +2,7 @@ /** * Resolves file/directory paths to modules they belong to * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Module\Dir; diff --git a/lib/internal/Magento/Framework/Module/FullModuleList.php b/lib/internal/Magento/Framework/Module/FullModuleList.php index 9cdb6cb3cf6dc..cea5b0e3eb60b 100644 --- a/lib/internal/Magento/Framework/Module/FullModuleList.php +++ b/lib/internal/Magento/Framework/Module/FullModuleList.php @@ -1,6 +1,6 @@ isEnabled('Vendor_Module') */ -namespace Magento\Framework\Module; - class Manager { /** - * @var Output\ConfigInterface + * The checker of output modules. + * + * @var Output\ConfigInterface the config checker of output modules. + * @deprecated */ - private $_outputConfig; + private $outputConfig; /** - * @var ModuleListInterface + * The list of all modules. + * + * @var ModuleListInterface the list of all modules. */ - private $_moduleList; + private $moduleList; /** - * @var array + * The list of config paths to ignore. + * + * @var array the list of config paths to ignore. + * @deprecated */ - private $_outputConfigPaths; + private $outputConfigPaths; /** - * @param Output\ConfigInterface $outputConfig - * @param ModuleListInterface $moduleList - * @param array $outputConfigPaths + * Constructor. + * + * @param Output\ConfigInterface $outputConfig the checker of output modules + * @param ModuleListInterface $moduleList the list of all modules + * @param array $outputConfigPaths the list of config paths to ignore */ public function __construct( Output\ConfigInterface $outputConfig, ModuleListInterface $moduleList, array $outputConfigPaths = [] ) { - $this->_outputConfig = $outputConfig; - $this->_moduleList = $moduleList; - $this->_outputConfigPaths = $outputConfigPaths; + $this->outputConfig = $outputConfig; + $this->moduleList = $moduleList; + $this->outputConfigPaths = $outputConfigPaths; } /** - * Whether a module is enabled in the configuration or not + * Checks whether a module is enabled in the configuration or not. * - * @param string $moduleName Fully-qualified module name - * @return boolean + * @param string $moduleName the fully-qualified module name + * + * @return boolean true if module is enabled, false otherwise */ public function isEnabled($moduleName) { - return $this->_moduleList->has($moduleName); + return $this->moduleList->has($moduleName); } /** - * Whether a module output is permitted by the configuration or not + * Checks whether a module output is permitted by the configuration or not. + * + * @param string $moduleName the fully-qualified module name. * - * @param string $moduleName Fully-qualified module name * @return boolean + * @deprecated + * @see \Magento\Framework\Module\Manager::isEnabled() */ public function isOutputEnabled($moduleName) { - if (!$this->isEnabled($moduleName)) { - return false; - } - if (!$this->_isCustomOutputConfigEnabled($moduleName)) { - return false; - } - if ($this->_outputConfig->isEnabled($moduleName)) { - return false; - } - return true; + return $this->isEnabled($moduleName); } /** - * Whether a configuration switch for a module output permits output or not + * Checks whether a configuration switch for a module output permits output. * * @param string $moduleName Fully-qualified module name + * * @return boolean + * @deprecated + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ protected function _isCustomOutputConfigEnabled($moduleName) { - if (isset($this->_outputConfigPaths[$moduleName])) { - $configPath = $this->_outputConfigPaths[$moduleName]; - if (defined($configPath)) { - $configPath = constant($configPath); - } - return $this->_outputConfig->isSetFlag($configPath); - } return true; } } diff --git a/lib/internal/Magento/Framework/Module/ModuleList.php b/lib/internal/Magento/Framework/Module/ModuleList.php index caaa5aba3153e..3c1605bed2eb7 100644 --- a/lib/internal/Magento/Framework/Module/ModuleList.php +++ b/lib/internal/Magento/Framework/Module/ModuleList.php @@ -1,6 +1,6 @@ isSetFlag(sprintf(self::XML_PATH_MODULE_OUTPUT_STATUS, $moduleName)); + return false; } /** @@ -49,6 +52,6 @@ public function isEnabled($moduleName) */ public function isSetFlag($path) { - return $this->_scopeConfig->isSetFlag($path, $this->_storeType); + return false; } } diff --git a/lib/internal/Magento/Framework/Module/Output/ConfigInterface.php b/lib/internal/Magento/Framework/Module/Output/ConfigInterface.php index 2794c424fbe8a..2025f5c6f42c5 100644 --- a/lib/internal/Magento/Framework/Module/Output/ConfigInterface.php +++ b/lib/internal/Magento/Framework/Module/Output/ConfigInterface.php @@ -1,10 +1,13 @@ diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/DependencyCheckerTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/DependencyCheckerTest.php index 2c199d5bcf797..301541f4d0f0b 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/DependencyCheckerTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/DependencyCheckerTest.php @@ -1,6 +1,6 @@ _moduleList = $this->getMockForAbstractClass(\Magento\Framework\Module\ModuleListInterface::class); - $this->_moduleList->expects($this->any()) - ->method('getOne') - ->will($this->returnValueMap([ - ['Module_One', ['name' => 'One_Module', 'setup_version' => '1']], - ['Module_Two', ['name' => 'Two_Module', 'setup_version' => '2']], - ['Module_Three', ['name' => 'Two_Three']], - ])); - $this->_outputConfig = $this->getMockForAbstractClass(\Magento\Framework\Module\Output\ConfigInterface::class); - $this->_model = new \Magento\Framework\Module\Manager( - $this->_outputConfig, - $this->_moduleList, - [ - 'Module_Two' => self::XML_PATH_OUTPUT_ENABLED, - ] + $this->moduleList = $this->getMockBuilder(ModuleListInterface::class) + ->getMockForAbstractClass(); + $this->outputConfig = $this->getMockBuilder(ConfigInterface::class) + ->getMockForAbstractClass(); + + $this->model = new Manager( + $this->outputConfig, + $this->moduleList ); } public function testIsEnabled() { - $this->_moduleList->expects($this->exactly(2))->method('has')->will($this->returnValueMap([ - ['Module_Exists', true], - ['Module_NotExists', false], - ])); - $this->assertTrue($this->_model->isEnabled('Module_Exists')); - $this->assertFalse($this->_model->isEnabled('Module_NotExists')); - } - - public function testIsOutputEnabledReturnsFalseForDisabledModule() - { - $this->_outputConfig->expects($this->any())->method('isSetFlag')->will($this->returnValue(true)); - $this->assertFalse($this->_model->isOutputEnabled('Disabled_Module')); - } - - /** - * @param bool $configValue - * @param bool $expectedResult - * @dataProvider isOutputEnabledGenericConfigPathDataProvider - */ - public function testIsOutputEnabledGenericConfigPath($configValue, $expectedResult) - { - $this->_moduleList->expects($this->once())->method('has')->will($this->returnValue(true)); - $this->_outputConfig->expects($this->once()) - ->method('isEnabled') - ->with('Module_One') - ->will($this->returnValue($configValue)); - $this->assertEquals($expectedResult, $this->_model->isOutputEnabled('Module_One')); - } + $this->moduleList->expects($this->exactly(2)) + ->method('has') + ->willReturnMap( + [ + ['Module_Exists', true], + ['Module_NotExists', false], + ] + ); - public function isOutputEnabledGenericConfigPathDataProvider() - { - return ['output disabled' => [true, false], 'output enabled' => [false, true]]; - } - - /** - * @param bool $configValue - * @param bool $expectedResult - * @dataProvider isOutputEnabledCustomConfigPathDataProvider - */ - public function testIsOutputEnabledCustomConfigPath($configValue, $expectedResult) - { - $this->_moduleList->expects($this->once())->method('has')->will($this->returnValue(true)); - $this->_outputConfig->expects($this->at(0)) - ->method('isSetFlag') - ->with(self::XML_PATH_OUTPUT_ENABLED) - ->will($this->returnValue($configValue)); - $this->assertEquals($expectedResult, $this->_model->isOutputEnabled('Module_Two')); - } - - public function isOutputEnabledCustomConfigPathDataProvider() - { - return [ - 'path literal, output disabled' => [false, false], - 'path literal, output enabled' => [true, true], - ]; + $this->assertTrue($this->model->isEnabled('Module_Exists')); + $this->assertFalse($this->model->isEnabled('Module_NotExists')); } } diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/ModuleList/LoaderTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/ModuleList/LoaderTest.php index 5c5a64f53a086..d2a51746067ff 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/ModuleList/LoaderTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/ModuleList/LoaderTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Mview/ActionFactory.php b/lib/internal/Magento/Framework/Mview/ActionFactory.php index 77b0c89c8cc39..af65ca15cb424 100644 --- a/lib/internal/Magento/Framework/Mview/ActionFactory.php +++ b/lib/internal/Magento/Framework/Mview/ActionFactory.php @@ -1,6 +1,6 @@ stateCollection = $stateCollection; $isCacheExists = $cache->test($cacheId); - parent::__construct($reader, $cache, $cacheId); + parent::__construct($reader, $cache, $cacheId, $serializer); if (!$isCacheExists) { $this->deleteNonexistentStates(); diff --git a/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php b/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php index 694d88e63ae47..c2e4c75b433fa 100644 --- a/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php +++ b/lib/internal/Magento/Framework/Mview/Config/Data/Proxy.php @@ -1,6 +1,6 @@ [], 'view3' => []]; + private $views = ['view1' => [], 'view3' => []]; + + /** + * @var \Magento\Framework\Serialize\SerializerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $serializerMock; protected function setUp() { @@ -58,28 +63,29 @@ protected function setUp() true, ['getItems'] ); + + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); } public function testConstructorWithCache() { $this->cache->expects($this->once())->method('test')->with($this->cacheId)->will($this->returnValue(true)); - $this->cache->expects( - $this->once() - )->method( - 'load' - )->with( - $this->cacheId - )->will( - $this->returnValue(serialize($this->views)) - ); + $this->cache->expects($this->once()) + ->method('load') + ->with($this->cacheId); $this->stateCollection->expects($this->never())->method('getItems'); - $this->model = new \Magento\Framework\Mview\Config\Data( + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn($this->views); + + $this->config = new \Magento\Framework\Mview\Config\Data( $this->reader, $this->cache, $this->stateCollection, - $this->cacheId + $this->cacheId, + $this->serializerMock ); } @@ -114,11 +120,12 @@ public function testConstructorWithoutCache() $this->stateCollection->expects($this->once())->method('getItems')->will($this->returnValue($states)); - $this->model = new \Magento\Framework\Mview\Config\Data( + $this->config = new \Magento\Framework\Mview\Config\Data( $this->reader, $this->cache, $this->stateCollection, - $this->cacheId + $this->cacheId, + $this->serializerMock ); } } diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php index a0f8e377862d0..cb81c9932d366 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/Config/ReaderTest.php @@ -1,6 +1,6 @@ connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, [], [], '', false); - $this->resourceMock = $this->getMock( - \Magento\Framework\App\ResourceConnection::class, - [], - [], - '', - false, - false + $this->resourceMock = $this->getMock( + \Magento\Framework\App\ResourceConnection::class, + [], + [], + '', + false, + false ); $this->connectionMock->expects($this->any()) @@ -57,19 +57,19 @@ protected function setUp() ->method('getConnection') ->willReturn($this->connectionMock); - $this->triggerFactoryMock = $this->getMock( + $this->triggerFactoryMock = $this->getMock( \Magento\Framework\DB\Ddl\TriggerFactory::class, [], [], '', false, false ); - $this->viewCollectionMock = $this->getMockForAbstractClass( + $this->viewCollectionMock = $this->getMockForAbstractClass( \Magento\Framework\Mview\View\CollectionInterface::class, [], '', false, false, true, [] ); - $this->viewMock = $this->getMockForAbstractClass( + $this->viewMock = $this->getMockForAbstractClass( \Magento\Framework\Mview\ViewInterface::class, [], '', false, false, true, [] ); $this->resourceMock->expects($this->any()) ->method('getTableName') - ->willReturn($this->tableName); + ->will($this->returnArgument(0)); $this->model = new Subscription( $this->resourceMock, @@ -96,11 +96,15 @@ public function testGetColumnName() $this->assertEquals('columnName', $this->model->getColumnName()); } + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ public function testCreate() { $triggerName = 'trigger_name'; $this->resourceMock->expects($this->atLeastOnce())->method('getTriggerName')->willReturn($triggerName); $triggerMock = $this->getMockBuilder(\Magento\Framework\DB\Ddl\Trigger::class) + ->setMethods(['setName', 'getName', 'setTime', 'setEvent', 'setTable', 'addStatement']) ->disableOriginalConstructor() ->getMock(); $triggerMock->expects($this->exactly(3)) @@ -121,11 +125,38 @@ public function testCreate() ->method('setTable') ->with($this->tableName) ->will($this->returnSelf()); - $triggerMock->expects($this->exactly(6)) + + $triggerMock->expects($this->at(4)) + ->method('addStatement') + ->with("INSERT IGNORE INTO test_view_cl (entity_id) VALUES (NEW.columnName);") + ->will($this->returnSelf()); + + $triggerMock->expects($this->at(5)) + ->method('addStatement') + ->with("INSERT IGNORE INTO other_test_view_cl (entity_id) VALUES (NEW.columnName);") + ->will($this->returnSelf()); + + $triggerMock->expects($this->at(11)) + ->method('addStatement') + ->with("INSERT IGNORE INTO test_view_cl (entity_id) VALUES (NEW.columnName);") + ->will($this->returnSelf()); + + $triggerMock->expects($this->at(12)) + ->method('addStatement') + ->with("INSERT IGNORE INTO other_test_view_cl (entity_id) VALUES (NEW.columnName);") + ->will($this->returnSelf()); + + $triggerMock->expects($this->at(18)) + ->method('addStatement') + ->with("INSERT IGNORE INTO test_view_cl (entity_id) VALUES (OLD.columnName);") + ->will($this->returnSelf()); + + $triggerMock->expects($this->at(19)) ->method('addStatement') + ->with("INSERT IGNORE INTO other_test_view_cl (entity_id) VALUES (OLD.columnName);") ->will($this->returnSelf()); - $changelogMock = $this->getMockForAbstractClass( + $changelogMock = $this->getMockForAbstractClass( \Magento\Framework\Mview\View\ChangelogInterface::class, [], '', false, false, true, [] ); $changelogMock->expects($this->exactly(3)) @@ -143,7 +174,7 @@ public function testCreate() ->method('create') ->will($this->returnValue($triggerMock)); - $otherChangelogMock = $this->getMockForAbstractClass( + $otherChangelogMock = $this->getMockForAbstractClass( \Magento\Framework\Mview\View\ChangelogInterface::class, [], '', false, false, true, [] ); $otherChangelogMock->expects($this->exactly(3)) @@ -153,7 +184,7 @@ public function testCreate() ->method('getColumnName') ->will($this->returnValue('entity_id')); - $otherViewMock = $this->getMockForAbstractClass( + $otherViewMock = $this->getMockForAbstractClass( \Magento\Framework\Mview\ViewInterface::class, [], '', false, false, true, [] ); $otherViewMock->expects($this->exactly(1)) @@ -216,7 +247,7 @@ public function testRemove() ->method('create') ->will($this->returnValue($triggerMock)); - $otherChangelogMock = $this->getMockForAbstractClass( + $otherChangelogMock = $this->getMockForAbstractClass( \Magento\Framework\Mview\View\ChangelogInterface::class, [], '', false, false, true, [] ); $otherChangelogMock->expects($this->exactly(3)) @@ -226,7 +257,7 @@ public function testRemove() ->method('getColumnName') ->will($this->returnValue('entity_id')); - $otherViewMock = $this->getMockForAbstractClass( + $otherViewMock = $this->getMockForAbstractClass( \Magento\Framework\Mview\ViewInterface::class, [], '', false, false, true, [] ); $otherViewMock->expects($this->exactly(1)) diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php index cf17286af0e9e..5371b8470bc66 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_merged_two.xml b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_merged_two.xml index 32d049f1570cf..030dc1b7c16fc 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_merged_two.xml +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_merged_two.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_one.xml b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_one.xml index 1ec8400e7f303..f6da086def77b 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_one.xml +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_one.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_three.xml b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_three.xml index a0ee312109cd4..340a12f306d1d 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_three.xml +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_three.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_two.xml b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_two.xml index 7e67bee354883..1553d12eaadb0 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_two.xml +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_two.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/valid_mview.xml b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/valid_mview.xml index d53d88943faf5..c4bba92f9955b 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/valid_mview.xml +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/valid_mview.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index 16d88767e508c..80b743b3f87fa 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -1,6 +1,6 @@ @@ -106,7 +106,7 @@ - Subscription model must be a valid PHP class or interface name. + DEPRECATED. Subscription model must be a valid PHP class or interface name. diff --git a/lib/internal/Magento/Framework/Notification/MessageInterface.php b/lib/internal/Magento/Framework/Notification/MessageInterface.php index cb5392b1114fe..70cf1637e412c 100644 --- a/lib/internal/Magento/Framework/Notification/MessageInterface.php +++ b/lib/internal/Magento/Framework/Notification/MessageInterface.php @@ -2,7 +2,7 @@ /** * System message * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Notification/MessageList.php b/lib/internal/Magento/Framework/Notification/MessageList.php index 87e0905f89229..dcaa6e04618b8 100644 --- a/lib/internal/Magento/Framework/Notification/MessageList.php +++ b/lib/internal/Magento/Framework/Notification/MessageList.php @@ -1,6 +1,6 @@ arguments[$type])) { if (is_string($this->arguments[$type])) { - $this->arguments[$type] = unserialize($this->arguments[$type]); + $this->arguments[$type] = $this->getSerializer()->unserialize($this->arguments[$type]); } return $this->arguments[$type]; } else { @@ -129,9 +141,15 @@ public function getPreference($type) */ public function extend(array $configuration) { - $this->arguments = $configuration['arguments']; - $this->virtualTypes = $configuration['instanceTypes']; - $this->preferences = $configuration['preferences']; + $this->arguments = isset($configuration['arguments']) + ? array_replace($this->arguments, $configuration['arguments']) + : $this->arguments; + $this->virtualTypes = isset($configuration['instanceTypes']) + ? array_replace($this->virtualTypes, $configuration['instanceTypes']) + : $this->virtualTypes; + $this->preferences = isset($configuration['preferences']) + ? array_replace($this->preferences, $configuration['preferences']) + : $this->preferences; } /** @@ -153,4 +171,19 @@ public function getPreferences() { return $this->preferences; } + + /** + * Get serializer + * + * @return SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if (null === $this->serializer) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(Serialize::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/ObjectManager/Config/Config.php b/lib/internal/Magento/Framework/ObjectManager/Config/Config.php index 5dc02e6ba7d97..e94699730cdcd 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Config/Config.php +++ b/lib/internal/Magento/Framework/ObjectManager/Config/Config.php @@ -1,10 +1,11 @@ _cache) { if (!$this->_currentCacheKey) { $this->_currentCacheKey = md5( - serialize([$this->_arguments, $this->_nonShared, $this->_preferences, $this->_virtualTypes]) + $this->getSerializer()->serialize( + [$this->_arguments, $this->_nonShared, $this->_preferences, $this->_virtualTypes] + ) ); } - $key = md5($this->_currentCacheKey . serialize($configuration)); + $key = md5($this->_currentCacheKey . $this->getSerializer()->serialize($configuration)); $cached = $this->_cache->get($key); if ($cached) { list( @@ -323,4 +331,19 @@ public function getPreferences() { return $this->_preferences; } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/ObjectManager/Config/Mapper/ArgumentParser.php b/lib/internal/Magento/Framework/ObjectManager/Config/Mapper/ArgumentParser.php index dc7463c0b1735..dfd2aa596b211 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Config/Mapper/ArgumentParser.php +++ b/lib/internal/Magento/Framework/ObjectManager/Config/Mapper/ArgumentParser.php @@ -1,6 +1,6 @@ _signatures, $this->_definitions) = $definitions; - $this->reader = $reader ?: new \Magento\Framework\Code\Reader\ClassReader(); - } - - /** - * Unpack signature - * - * @param string $signature - * @return mixed - */ - abstract protected function _unpack($signature); - - /** - * Get list of method parameters - * - * Retrieve an ordered list of constructor parameters. - * Each value is an array with following entries: - * - * array( - * 0, // string: Parameter name - * 1, // string|null: Parameter type - * 2, // bool: whether this param is required - * 3, // mixed: default value - * ); - * - * @param string $className - * @return array|null - */ - public function getParameters($className) - { - // if the definition isn't found in the list gathered from the compiled file then using reflection to find it - if (!array_key_exists($className, $this->_definitions)) { - return $this->reader->getConstructor($className); - } - - $definition = $this->_definitions[$className]; - if ($definition !== null) { - if (is_string($this->_signatures[$definition])) { - $this->_signatures[$definition] = $this->_unpack($this->_signatures[$definition]); - } - return $this->_signatures[$definition]; - } - return null; - } - - /** - * Retrieve list of all classes covered with definitions - * - * @return array - */ - public function getClasses() - { - return array_keys($this->_definitions); - } -} diff --git a/lib/internal/Magento/Framework/ObjectManager/Definition/Compiled/Binary.php b/lib/internal/Magento/Framework/ObjectManager/Definition/Compiled/Binary.php deleted file mode 100644 index bba816e072e6b..0000000000000 --- a/lib/internal/Magento/Framework/ObjectManager/Definition/Compiled/Binary.php +++ /dev/null @@ -1,27 +0,0 @@ - \Magento\Framework\ObjectManager\Definition\Compiled\Binary::class, - Serialized::MODE_NAME => \Magento\Framework\ObjectManager\Definition\Compiled\Serialized::class, - ]; - /** * @var \Magento\Framework\Code\Generator */ @@ -74,39 +38,26 @@ class DefinitionFactory /** * @param DriverInterface $filesystemDriver - * @param string $definitionDir * @param string $generationDir - * @param string $definitionFormat */ - public function __construct(DriverInterface $filesystemDriver, $definitionDir, $generationDir, $definitionFormat) - { + public function __construct( + DriverInterface $filesystemDriver, + $generationDir + ) { $this->_filesystemDriver = $filesystemDriver; - $this->_definitionDir = $definitionDir; $this->_generationDir = $generationDir; - $this->_definitionFormat = $definitionFormat; } /** * Create class definitions * - * @param mixed $definitions - * @return Runtime + * @return DefinitionInterface */ - public function createClassDefinition($definitions = false) + public function createClassDefinition() { - if ($definitions) { - if (is_string($definitions)) { - $definitions = $this->_unpack($definitions); - } - $definitionModel = self::$definitionClasses[$this->_definitionFormat]; - $result = new $definitionModel($definitions); - } else { - $autoloader = new \Magento\Framework\Code\Generator\Autoloader($this->getCodeGenerator()); - spl_autoload_register([$autoloader, 'load']); - - $result = new Runtime(); - } - return $result; + $autoloader = new Autoloader($this->getCodeGenerator()); + spl_autoload_register([$autoloader, 'load']); + return new Runtime(); } /** @@ -116,14 +67,7 @@ public function createClassDefinition($definitions = false) */ public function createPluginDefinition() { - $path = $this->_definitionDir . '/plugins.ser'; - if ($this->_filesystemDriver->isReadable($path)) { - return new \Magento\Framework\Interception\Definition\Compiled( - $this->_unpack($this->_filesystemDriver->fileGetContents($path)) - ); - } else { - return new \Magento\Framework\Interception\Definition\Runtime(); - } + return new \Magento\Framework\Interception\Definition\Runtime(); } /** @@ -133,36 +77,7 @@ public function createPluginDefinition() */ public function createRelations() { - $path = $this->_definitionDir . '/' . 'relations.ser'; - if ($this->_filesystemDriver->isReadable($path)) { - return new \Magento\Framework\ObjectManager\Relations\Compiled( - $this->_unpack($this->_filesystemDriver->fileGetContents($path)) - ); - } else { - return new \Magento\Framework\ObjectManager\Relations\Runtime(); - } - } - - /** - * Gets supported definition formats - * - * @return array - */ - public static function getSupportedFormats() - { - return array_keys(self::$definitionClasses); - } - - /** - * Un-compress definitions - * - * @param string $definitions - * @return mixed - */ - protected function _unpack($definitions) - { - $extractor = $this->_definitionFormat == Binary::MODE_NAME ? 'igbinary_unserialize' : 'unserialize'; - return $extractor($definitions); + return new \Magento\Framework\ObjectManager\Relations\Runtime(); } /** diff --git a/lib/internal/Magento/Framework/ObjectManager/DefinitionInterface.php b/lib/internal/Magento/Framework/ObjectManager/DefinitionInterface.php index f330c101b749f..9cd2cb1dec8a4 100644 --- a/lib/internal/Magento/Framework/ObjectManager/DefinitionInterface.php +++ b/lib/internal/Magento/Framework/ObjectManager/DefinitionInterface.php @@ -2,7 +2,7 @@ /** * Object Manager class definition interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\ObjectManager; diff --git a/lib/internal/Magento/Framework/ObjectManager/DynamicConfigInterface.php b/lib/internal/Magento/Framework/ObjectManager/DynamicConfigInterface.php index 319572c6fd8a9..dd399c33ccb1f 100644 --- a/lib/internal/Magento/Framework/ObjectManager/DynamicConfigInterface.php +++ b/lib/internal/Magento/Framework/ObjectManager/DynamicConfigInterface.php @@ -1,6 +1,6 @@ _relations = $relations; - } - - /** - * Check whether requested type is available for read - * - * @param string $type - * @return bool - */ - public function has($type) - { - return isset($this->_relations[$type]); - } - - /** - * Retrieve parents for class - * - * @param string $type - * @return array - */ - public function getParents($type) - { - return $this->_relations[$type]; - } -} diff --git a/lib/internal/Magento/Framework/ObjectManager/Relations/Runtime.php b/lib/internal/Magento/Framework/ObjectManager/Relations/Runtime.php index 7e6ac27814541..92d72b14c120d 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Relations/Runtime.php +++ b/lib/internal/Magento/Framework/ObjectManager/Relations/Runtime.php @@ -1,6 +1,6 @@ objectManager = new ObjectManager($this); + $this->serializerMock = $this->getMock(SerializerInterface::class); + } + + public function testExtend() + { + $initialData = [ + 'arguments' => [ + 'type1' => 'initial serialized configuration for type1' + ], + 'instanceTypes' => [ + 'instanceType1' => 'instanceTypeValue1', + 'instanceType2' => 'instanceTypeValue2' + ], + 'preferences' => [ + 'preference1' => 'preferenceValue1', + 'preference2' => 'preferenceValue2' + ] + ]; + $configuration = [ + 'arguments' => [ + 'type1' => 'serialized configuration for type1', + 'type2' => 'serialized configuration for type2' + ], + 'instanceTypes' => [ + 'instanceType2' => 'newInstanceTypeValue2', + 'instanceType3' => 'newInstanceTypeValue3' + ], + 'preferences' => [ + 'preference1' => 'newPreferenceValue1' + ] + ]; + $expectedArguments = [ + 'type1' => [ + 'argument1_1' => 'newArgumentValue1_1' + ], + 'type2' => [ + 'argument2_1' => 'newArgumentValue2_1' + ] + ]; + $expectedVirtualTypes = [ + 'instanceType1' => 'instanceTypeValue1', + 'instanceType2' => 'newInstanceTypeValue2', + 'instanceType3' => 'newInstanceTypeValue3' + ]; + $expectedPreferences = [ + 'preference1' => 'newPreferenceValue1', + 'preference2' => 'preferenceValue2' + ]; + $this->serializerMock->expects($this->at(0)) + ->method('unserialize') + ->with($configuration['arguments']['type1']) + ->willReturn($expectedArguments['type1']); + $this->serializerMock->expects($this->at(1)) + ->method('unserialize') + ->with($configuration['arguments']['type2']) + ->willReturn($expectedArguments['type2']); + $compiled = $this->objectManager->getObject( + Compiled::class, + [ + 'data' => $initialData, + 'serializer' => $this->serializerMock + ] + ); + $compiled->extend($configuration); + foreach ($expectedArguments as $type => $arguments) { + $this->assertEquals($arguments, $compiled->getArguments($type)); + } + $this->assertEquals($expectedVirtualTypes, $compiled->getVirtualTypes()); + $this->assertEquals($expectedPreferences, $compiled->getPreferences()); + } +} diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/ConfigTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/ConfigTest.php index 844d5fa94a627..29561991f28d0 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/ConfigTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/ConfigTest.php @@ -1,14 +1,23 @@ objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + } + public function testGetArgumentsEmpty() { $config = new Config(); @@ -42,6 +51,14 @@ public function testExtendWithCacheMock() $cache->expects($this->once())->method('get')->will($this->returnValue(false)); $config = new Config(null, $definitions); + $serializerMock = $this->getMock(SerializerInterface::class); + $serializerMock->expects($this->exactly(2)) + ->method('serialize'); + $this->objectManagerHelper->setBackwardCompatibleProperty( + $config, + 'serializer', + $serializerMock + ); $config->setCache($cache); $this->_assertFooTypeArguments($config); diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/ArgumentParserTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/ArgumentParserTest.php index d3907cfece779..c38a8e11f7c78 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/ArgumentParserTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/ArgumentParserTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/_files/mapped_simple_di_config.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/_files/mapped_simple_di_config.php index dd94048d59d84..eb20fa307f718 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/_files/mapped_simple_di_config.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Mapper/_files/mapped_simple_di_config.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Reader/DomFactoryTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Reader/DomFactoryTest.php index 2f5c6027d0f1f..1ec8c28e20390 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Reader/DomFactoryTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/Reader/DomFactoryTest.php @@ -1,6 +1,6 @@ [ + ' + + + + + Some_Class_Name + + + + ', + [ + "Element 'item', attribute 'sortOrder': 'false' is not a valid value of the atomic type 'xs:integer'." . + "\nLine: 6\n" + ], + ], ]; diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/_files/valid_config.xml b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/_files/valid_config.xml index df900f0ce4a9c..852a3b3163339 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/_files/valid_config.xml +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Config/_files/valid_config.xml @@ -1,7 +1,7 @@ @@ -57,6 +57,11 @@ some_value + + Instance_test_name_two + Instance_test_name_one + Instance_test_name_three + diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/Compiled/BinaryTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/Compiled/BinaryTest.php deleted file mode 100644 index 80cf73a44e7ac..0000000000000 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/Compiled/BinaryTest.php +++ /dev/null @@ -1,21 +0,0 @@ -markTestSkipped('This test requires igbinary PHP extension'); - } - $checkString = 'packed code'; - $signatures = ['wonderfulClass' => igbinary_serialize($checkString)]; - $definitions = ['wonderful' => 'wonderfulClass']; - $model = new \Magento\Framework\ObjectManager\Definition\Compiled\Binary([$signatures, $definitions]); - $this->assertEquals($checkString, $model->getParameters('wonderful')); - } -} diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/Compiled/SerializedTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/Compiled/SerializedTest.php deleted file mode 100644 index 9454377c3b720..0000000000000 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/Compiled/SerializedTest.php +++ /dev/null @@ -1,35 +0,0 @@ - null]; - $model = new \Magento\Framework\ObjectManager\Definition\Compiled\Serialized([$signatures, $definitions]); - $this->assertEquals(null, $model->getParameters('wonderful')); - } - - public function testGetParametersWithSignatureObject() - { - $wonderfulSignature = new \stdClass(); - $signatures = ['wonderfulClass' => $wonderfulSignature]; - $definitions = ['wonderful' => 'wonderfulClass']; - $model = new \Magento\Framework\ObjectManager\Definition\Compiled\Serialized([$signatures, $definitions]); - $this->assertEquals($wonderfulSignature, $model->getParameters('wonderful')); - } - - public function testGetParametersWithUnpacking() - { - $checkString = 'code to pack'; - $signatures = ['wonderfulClass' => serialize($checkString)]; - $definitions = ['wonderful' => 'wonderfulClass']; - $model = new \Magento\Framework\ObjectManager\Definition\Compiled\Serialized([$signatures, $definitions]); - $this->assertEquals($checkString, $model->getParameters('wonderful')); - } -} diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/CompiledStub.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/CompiledStub.php deleted file mode 100644 index 16b8436a0c41a..0000000000000 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Definition/CompiledStub.php +++ /dev/null @@ -1,25 +0,0 @@ -getMock( - \Magento\Framework\Code\Reader\ClassReader::class, - ['getConstructor'], - [], - '', - false - ); - $readerMock->expects($this->once()) - ->method('getConstructor') - ->with($className) - ->willReturn($undefinedDefinitionSignature); - $model = $objectManager->getObject( - \Magento\Framework\ObjectManager\Test\Unit\Definition\CompiledStub::class, - [ - 'definitions' => [[], []], - 'reader' => $readerMock - ] - ); - $this->assertEquals($undefinedDefinitionSignature, $model->getParameters($className)); - } -} diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/DefinitionFactoryTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/DefinitionFactoryTest.php index 468e01ce80aba..9d61b925e2141 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/DefinitionFactoryTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/DefinitionFactoryTest.php @@ -1,121 +1,58 @@ sampleContent = serialize([1, 2, 3]); - $this->filesystemDriverMock = $this->getMock( - \Magento\Framework\Filesystem\Driver\File::class, - [], - [], - '', - false - ); - $this->model = new \Magento\Framework\ObjectManager\DefinitionFactory( + $this->filesystemDriverMock = $this->getMock(File::class); + $this->definitionFactory = new DefinitionFactory( $this->filesystemDriverMock, - 'DefinitionDir', - 'GenerationDir', - Serialized::MODE_NAME + 'generation dir' ); } - public function testCreateClassDefinitionFromString() + public function testCreateClassDefinition() { $this->assertInstanceOf( - \Magento\Framework\ObjectManager\Definition\Compiled\Serialized::class, - $this->model->createClassDefinition($this->sampleContent) + DefinitionInterface::class, + $this->definitionFactory->createClassDefinition() ); } - /** - * @param string $path - * @param string $callMethod - * @param string $expectedClass - * @dataProvider createPluginsAndRelationsReadableDataProvider - */ - public function testCreatePluginsAndRelationsReadable($path, $callMethod, $expectedClass) - { - $this->filesystemDriverMock->expects($this->once())->method('isReadable') - ->with($path) - ->will($this->returnValue(true)); - $this->filesystemDriverMock->expects($this->once())->method('fileGetContents') - ->with($path) - ->will($this->returnValue($this->sampleContent)); - $this->assertInstanceOf($expectedClass, $this->model->$callMethod()); - } - - public function createPluginsAndRelationsReadableDataProvider() - { - return [ - 'relations' => [ - 'DefinitionDir/relations.ser', - 'createRelations', \Magento\Framework\ObjectManager\Relations\Compiled::class, - ], - 'plugins' => [ - 'DefinitionDir/plugins.ser', - 'createPluginDefinition', \Magento\Framework\Interception\Definition\Compiled::class, - ], - ]; - } - - /** - * @param string $path - * @param string $callMethod - * @param string $expectedClass - * @dataProvider createPluginsAndRelationsNotReadableDataProvider - */ - public function testCreatePluginsAndRelationsNotReadable($path, $callMethod, $expectedClass) + public function testCreatePluginDefinition() { - $this->filesystemDriverMock->expects($this->once())->method('isReadable') - ->with($path) - ->will($this->returnValue(false)); - $this->assertInstanceOf($expectedClass, $this->model->$callMethod()); - } - - public function createPluginsAndRelationsNotReadableDataProvider() - { - return [ - 'relations' => [ - 'DefinitionDir/relations.ser', - 'createRelations', \Magento\Framework\ObjectManager\Relations\Runtime::class, - ], - 'plugins' => [ - 'DefinitionDir/plugins.ser', - 'createPluginDefinition', \Magento\Framework\Interception\Definition\Runtime::class, - ], - ]; + $this->assertInstanceOf( + InterceptionDefinitionInterface::class, + $this->definitionFactory->createPluginDefinition() + ); } - public function testGetSupportedFormats() + public function testCreateRelations() { - $actual = \Magento\Framework\ObjectManager\DefinitionFactory::getSupportedFormats(); - $this->assertInternalType('array', $actual); - foreach ($actual as $className) { - $this->assertInternalType('string', $className); - } + $this->assertInstanceOf( + RelationsInterface::class, + $this->definitionFactory->createRelations() + ); } } diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/CompiledTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/CompiledTest.php index dbf7da6bb5eab..86c7498c872c4 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/CompiledTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Factory/CompiledTest.php @@ -1,6 +1,6 @@ 'yes']; - - $model = new \Magento\Framework\ObjectManager\Relations\Compiled($relations); - $this->assertEquals(true, $model->has('amazing')); - $this->assertEquals(false, $model->has('fuzzy')); - } - - public function testGetParents() - { - $relations = ['amazing' => 'parents']; - - $model = new \Magento\Framework\ObjectManager\Relations\Compiled($relations); - $this->assertEquals('parents', $model->getParents('amazing')); - } -} diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php index cb274f845b668..6c66dde1e80cd 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php +++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Relations/RuntimeTest.php @@ -1,6 +1,6 @@ @@ -20,6 +20,7 @@ + diff --git a/lib/internal/Magento/Framework/ObjectManagerInterface.php b/lib/internal/Magento/Framework/ObjectManagerInterface.php index e30b040866b74..6041f63d1e7d4 100644 --- a/lib/internal/Magento/Framework/ObjectManagerInterface.php +++ b/lib/internal/Magento/Framework/ObjectManagerInterface.php @@ -1,6 +1,6 @@ with($this->equalTo($totalAmount), $this->equalTo($expectedAdjustments)) ->will($this->returnValue($amountBaseMock)); - $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + $productMock = $this->getMockBuilder(\Magento\Framework\Pricing\SaleableInterface::class) ->disableOriginalConstructor() ->setMethods(['getPriceInfo', '__wakeup']) - ->getMock(); + ->getMockForAbstractClass(); - $weeeAdjustmentMock = $this->getMockBuilder(\Magento\Weee\Pricing\Adjustment::class) + $weeeAdjustmentMock = $this->getMockBuilder(\Magento\Framework\Pricing\Adjustment\AdjustmentInterface::class) ->disableOriginalConstructor() ->getMock(); $weeeAdjustmentMock->expects($this->once()) @@ -82,7 +82,7 @@ public function testGetAmount() ->with($this->equalTo($amountInclTax), $this->equalTo($productMock)) ->will($this->returnValue($weeeAdjustment + $amountInclTax)); - $taxAdjustmentMock = $this->getMockBuilder(\Magento\Tax\Pricing\Adjustment::class) + $taxAdjustmentMock = $this->getMockBuilder(\Magento\Framework\Pricing\Adjustment\AdjustmentInterface::class) ->disableOriginalConstructor() ->getMock(); $taxAdjustmentMock->expects($this->once()) @@ -127,12 +127,12 @@ public function testGetAmountExclude() $adjustment = 5; $expectedAdjustments = []; - $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + $productMock = $this->getMockBuilder(\Magento\Framework\Pricing\SaleableInterface::class) ->disableOriginalConstructor() ->setMethods(['getPriceInfo', '__wakeup']) - ->getMock(); + ->getMockForAbstractClass(); - $taxAdjustmentMock = $this->getMockBuilder(\Magento\Tax\Pricing\Adjustment::class) + $taxAdjustmentMock = $this->getMockBuilder(\Magento\Framework\Pricing\Adjustment\AdjustmentInterface::class) ->disableOriginalConstructor() ->getMock(); $taxAdjustmentMock->expects($this->once()) @@ -150,7 +150,7 @@ public function testGetAmountExclude() ->with($this->equalTo($fullamount), $this->equalTo($productMock)) ->will($this->returnValue($amount)); - $weeeAdjustmentMock = $this->getMockBuilder(\Magento\Weee\Pricing\Adjustment::class) + $weeeAdjustmentMock = $this->getMockBuilder(\Magento\Framework\Pricing\Adjustment\AdjustmentInterface::class) ->disableOriginalConstructor() ->getMock(); $weeeAdjustmentMock->expects($this->once()) diff --git a/lib/internal/Magento/Framework/Pricing/Test/Unit/Adjustment/CollectionTest.php b/lib/internal/Magento/Framework/Pricing/Test/Unit/Adjustment/CollectionTest.php index a156104b57388..ade0b98b835be 100644 --- a/lib/internal/Magento/Framework/Pricing/Test/Unit/Adjustment/CollectionTest.php +++ b/lib/internal/Magento/Framework/Pricing/Test/Unit/Adjustment/CollectionTest.php @@ -1,6 +1,6 @@ assertEquals($this->rendererPool, $this->model->getRendererPool()); } + + /** + * This tests ensures that protected method getCacheLifetime() returns a null value when cacheLifeTime is not + * explicitly set in the parent block + */ + public function testCacheLifetime() + { + $reflectionClass = new \ReflectionClass(get_class($this->model)); + $methodReflection = $reflectionClass->getMethod('getCacheLifetime'); + $methodReflection->setAccessible(true); + $cacheLifeTime = $methodReflection->invoke($this->model); + $this->assertNull($cacheLifeTime, 'Expected null cache lifetime'); + } } diff --git a/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/RendererPoolTest.php b/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/RendererPoolTest.php index 7d400b6933c54..5d16612d61045 100644 --- a/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/RendererPoolTest.php +++ b/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/RendererPoolTest.php @@ -1,6 +1,6 @@ disableOriginalConstructor() ->getMock(); - $this->price = $this->getMockBuilder(\Magento\Catalog\Pricing\Price\BasePrice::class) + $this->price = $this->getMockBuilder(\Magento\Framework\Pricing\Price\PriceInterface::class) ->disableOriginalConstructor() - ->getMock(); + ->getMockForAbstractClass(); $this->amount = $this->getMockBuilder(\Magento\Framework\Pricing\Amount\Base::class) ->disableOriginalConstructor() ->getMock(); - $this->saleableItem = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + $this->saleableItem = $this->getMockBuilder(\Magento\Framework\Pricing\SaleableInterface::class) ->disableOriginalConstructor() - ->getMock(); + ->getMockForAbstractClass(); $this->renderPool = $this->getMockBuilder(\Magento\Framework\Pricing\Render\RendererPool::class) ->disableOriginalConstructor() diff --git a/lib/internal/Magento/Framework/Process/PhpExecutableFinderFactory.php b/lib/internal/Magento/Framework/Process/PhpExecutableFinderFactory.php index 4780fd408d413..8328d021dc298 100644 --- a/lib/internal/Magento/Framework/Process/PhpExecutableFinderFactory.php +++ b/lib/internal/Magento/Framework/Process/PhpExecutableFinderFactory.php @@ -1,6 +1,6 @@ serviceInterfaceMethodsMap[$key])) { $methodMap = $this->cache->load($key); if ($methodMap) { - $this->serviceInterfaceMethodsMap[$key] = unserialize($methodMap); + $this->serviceInterfaceMethodsMap[$key] = $this->getSerializer()->unserialize($methodMap); } else { $methodMap = $this->getMethodMapViaReflection($interfaceName); $this->serviceInterfaceMethodsMap[$key] = $methodMap; - $this->cache->save(serialize($this->serviceInterfaceMethodsMap[$key]), $key); + $this->cache->save($this->getSerializer()->serialize($this->serviceInterfaceMethodsMap[$key]), $key); } } return $this->serviceInterfaceMethodsMap[$key]; @@ -117,7 +123,7 @@ public function getMethodParams($serviceClassName, $serviceMethodName) $cacheId = self::SERVICE_METHOD_PARAMS_CACHE_PREFIX . hash('md5', $serviceClassName . $serviceMethodName); $params = $this->cache->load($cacheId); if ($params !== false) { - return unserialize($params); + return $this->getSerializer()->unserialize($params); } $serviceClass = new ClassReflection($serviceClassName); /** @var MethodReflection $serviceMethod */ @@ -133,7 +139,7 @@ public function getMethodParams($serviceClassName, $serviceMethodName) self::METHOD_META_DEFAULT_VALUE => $isDefaultValueAvailable ? $paramReflection->getDefaultValue() : null ]; } - $this->cache->save(serialize($params), $cacheId, [ReflectionCache::CACHE_TAG]); + $this->cache->save($this->getSerializer()->serialize($params), $cacheId, [ReflectionCache::CACHE_TAG]); return $params; } @@ -217,4 +223,19 @@ public function isMethodReturnValueRequired($type, $methodName) $methods = $this->getMethodsMap($type); return $methods[$methodName]['isRequired']; } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/Reflection/NameFinder.php b/lib/internal/Magento/Framework/Reflection/NameFinder.php index 9de6125cf1d3d..4172d3f2715ae 100644 --- a/lib/internal/Magento/Framework/Reflection/NameFinder.php +++ b/lib/internal/Magento/Framework/Reflection/NameFinder.php @@ -1,6 +1,6 @@ getMockForAbstractClass(); $fieldNamerMock = $this->getMockBuilder(\Magento\Framework\Reflection\FieldNamer::class) ->getMockForAbstractClass(); - $this->model = $objectManager->getObject( + $this->object = $objectManager->getObject( \Magento\Framework\Reflection\MethodsMap::class, [ 'cache' => $cacheMock, @@ -48,27 +51,33 @@ protected function setUp() 'fieldNamer' => $fieldNamerMock, ] ); + $this->serializerMock = $this->getMock(SerializerInterface::class); + $objectManager->setBackwardCompatibleProperty( + $this->object, + 'serializer', + $this->serializerMock + ); } public function testGetMethodReturnType() { $this->assertEquals( 'string', - $this->model->getMethodReturnType( + $this->object->getMethodReturnType( \Magento\Framework\Reflection\FieldNamer::class, 'getFieldNameForMethodName' ) ); $this->assertEquals( 'mixed', - $this->model->getMethodReturnType( + $this->object->getMethodReturnType( \Magento\Framework\Reflection\TypeCaster::class, 'castValueToType' ) ); $this->assertEquals( 'array', - $this->model->getMethodReturnType( + $this->object->getMethodReturnType( \Magento\Framework\Reflection\MethodsMap::class, 'getMethodsMap' ) @@ -77,42 +86,46 @@ public function testGetMethodReturnType() public function testGetMethodsMap() { - $methodsMap = $this->model->getMethodsMap(\Magento\Framework\Reflection\MethodsMap::class); - $this->assertEquals( - [ - 'getMethodReturnType' => [ - 'type' => 'string', - 'isRequired' => true, - 'description' => null, - 'parameterCount' => 2, - ], - 'getMethodsMap' => [ - 'type' => 'array', - 'isRequired' => true, - 'description' => "
     Service methods' reflection data stored in cache as 'methodName' => "
    -                        . "'returnType' ex. [ 'create' => '\Magento\Customer\Api\Data\Customer', 'validatePassword' "
    -                        . "=> 'boolean' ] 
    ", - 'parameterCount' => 1, - ], - 'getMethodParams' => [ - 'type' => 'array', - 'isRequired' => true, - 'description' => null, - 'parameterCount' => 2 - ], - 'isMethodValidForDataField' => [ - 'type' => 'bool', - 'isRequired' => true, - 'description' => null, - 'parameterCount' => 2, - ], - 'isMethodReturnValueRequired' => [ - 'type' => 'bool', - 'isRequired' => true, - 'description' => null, - 'parameterCount' => 2, - ], + $data = [ + 'getMethodReturnType' => [ + 'type' => 'string', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 2, + ], + 'getMethodsMap' => [ + 'type' => 'array', + 'isRequired' => true, + 'description' => "
     Service methods' reflection data stored in cache as 'methodName' => "
    +                    . "'returnType' ex. [ 'create' => '\Magento\Customer\Api\Data\Customer', 'validatePassword' "
    +                    . "=> 'boolean' ] 
    ", + 'parameterCount' => 1, ], + 'getMethodParams' => [ + 'type' => 'array', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 2 + ], + 'isMethodValidForDataField' => [ + 'type' => 'bool', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 2, + ], + 'isMethodReturnValueRequired' => [ + 'type' => 'bool', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 2, + ], + ]; + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($data); + $methodsMap = $this->object->getMethodsMap(\Magento\Framework\Reflection\MethodsMap::class); + $this->assertEquals( + $data, $methodsMap ); } @@ -125,7 +138,7 @@ public function testGetMethodsMap() */ public function testIsMethodValidForDataField($type, $methodName, $expectedResult) { - $this->assertEquals($this->model->isMethodValidForDataField($type, $methodName), $expectedResult); + $this->assertEquals($this->object->isMethodValidForDataField($type, $methodName), $expectedResult); } /** @@ -157,7 +170,7 @@ public function isMethodValidForDataFieldProvider() */ public function testIsMethodReturnValueRequired($type, $methodName, $expectedResult) { - $this->assertEquals($this->model->isMethodValidForDataField($type, $methodName), $expectedResult); + $this->assertEquals($this->object->isMethodValidForDataField($type, $methodName), $expectedResult); } /** diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php index 6fa186ee5802e..363031309e334 100644 --- a/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/NameFinderTest.php @@ -1,6 +1,6 @@ columns @@ -30,7 +30,7 @@ public function build(RequestBucketInterface $bucket) foreach ($metrics as $metric) { $metricType = $metric->getType(); - if (in_array($metricType, $this->mapMetrics)) { + if (in_array($metricType, $this->allowedMetrics, true)) { $selectAggregations[$metricType] = "$metricType(main_table.value)"; } } diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Range.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Range.php index 2188657bd89ae..9cce6e2dbfadc 100644 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Range.php +++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Aggregation/Builder/Range.php @@ -1,6 +1,6 @@ request->expects($this->once())->method('getQuery')->will($this->returnValue($query)); - $select->expects($this->any())->method('columns')->will($this->returnValue($select)); + $select->expects($this->any())->method('columns')->willReturnSelf(); $response = $this->mapper->buildQuery($this->request); @@ -165,7 +165,7 @@ public function testBuildFilterQuery() ->method('getSize') ->willReturn(self::REQUEST_LIMIT); - $select->expects($this->any())->method('columns')->will($this->returnValue($select)); + $select->expects($this->any())->method('columns')->willReturnSelf(); $this->request->expects($this->once())->method('getQuery')->will($this->returnValue($query)); @@ -522,9 +522,9 @@ private function createSelectMock(Select $from = null, $isInternal = true, $isGr ->willReturnSelf(); } - $select->expects($isInternal ? $this->once() : $this->never()) + $select->expects($this->any()) ->method('limit') - ->with(self::REQUEST_LIMIT) + ->with($isInternal ? self::REQUEST_LIMIT : 10000000000) ->willReturnSelf(); $select->expects($isInternal ? $this->once() : $this->never()) ->method('order') diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/Builder/MatchTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/Builder/MatchTest.php index c677e045f6377..2626d68428c34 100644 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/Builder/MatchTest.php +++ b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/Query/Builder/MatchTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Search/etc/requests.xsd b/lib/internal/Magento/Framework/Search/etc/requests.xsd index f185699c5a5e8..67ce202c7f951 100644 --- a/lib/internal/Magento/Framework/Search/etc/requests.xsd +++ b/lib/internal/Magento/Framework/Search/etc/requests.xsd @@ -1,7 +1,7 @@ @@ -263,6 +263,7 @@ +
    diff --git a/lib/internal/Magento/Framework/Search/etc/search_engine.xsd b/lib/internal/Magento/Framework/Search/etc/search_engine.xsd index c6dad2d6b3f8c..3ca174a8d49c5 100644 --- a/lib/internal/Magento/Framework/Search/etc/search_engine.xsd +++ b/lib/internal/Magento/Framework/Search/etc/search_engine.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Search/etc/search_request.xsd b/lib/internal/Magento/Framework/Search/etc/search_request.xsd index e4ca02d9f0997..01851b1695d5a 100644 --- a/lib/internal/Magento/Framework/Search/etc/search_request.xsd +++ b/lib/internal/Magento/Framework/Search/etc/search_request.xsd @@ -1,7 +1,7 @@ @@ -25,4 +25,4 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Search/etc/search_request_merged.xsd b/lib/internal/Magento/Framework/Search/etc/search_request_merged.xsd index dab110ee5333a..b0243ae7e5b4c 100644 --- a/lib/internal/Magento/Framework/Search/etc/search_request_merged.xsd +++ b/lib/internal/Magento/Framework/Search/etc/search_request_merged.xsd @@ -1,7 +1,7 @@ @@ -32,4 +32,4 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Serialize/README.md b/lib/internal/Magento/Framework/Serialize/README.md new file mode 100644 index 0000000000000..5af8fb7f71b6b --- /dev/null +++ b/lib/internal/Magento/Framework/Serialize/README.md @@ -0,0 +1,8 @@ +# Serialize + +**Serialize** library provides interface *SerializerInterface* and multiple implementations: + + * *Json* - default implementation. Uses PHP native json_encode/json_decode functions; + * *Serialize* - less secure than *Json*, but gives higher performance on big arrays. Uses PHP native serialize/unserialize functions, does not unserialize objects on PHP 7. + +Using *Serialize* implementation directly is discouraged, always use *SerializerInterface*, using *Serialize* implementation may lead to security vulnerabilities. \ No newline at end of file diff --git a/lib/internal/Magento/Framework/Serialize/Serializer/Json.php b/lib/internal/Magento/Framework/Serialize/Serializer/Json.php new file mode 100644 index 0000000000000..24fadfcb0deee --- /dev/null +++ b/lib/internal/Magento/Framework/Serialize/Serializer/Json.php @@ -0,0 +1,30 @@ +getPhpVersion() >= 7) { + return unserialize($string, ['allowed_classes' => false]); + } + return unserialize($string); + } + + /** + * Return major PHP version + * + * @return int + */ + private function getPhpVersion() + { + return PHP_MAJOR_VERSION; + } +} diff --git a/lib/internal/Magento/Framework/Serialize/SerializerInterface.php b/lib/internal/Magento/Framework/Serialize/SerializerInterface.php new file mode 100644 index 0000000000000..3fc589fab7a8e --- /dev/null +++ b/lib/internal/Magento/Framework/Serialize/SerializerInterface.php @@ -0,0 +1,28 @@ +json = $objectManager->getObject(Json::class); + } + + /** + * @param string|int|float|bool|array|null $value + * @param string $expected + * @dataProvider serializeDataProvider + */ + public function testSerialize($value, $expected) + { + $this->assertEquals( + $expected, + $this->json->serialize($value) + ); + } + + public function serializeDataProvider() + { + $dataObject = new DataObject(['something']); + return [ + ['', '""'], + ['string', '"string"'], + [null, 'null'], + [false, 'false'], + [['a' => 'b', 'd' => 123], '{"a":"b","d":123}'], + [123, '123'], + [10.56, '10.56'], + [$dataObject, '{}'], + ]; + } + + /** + * @param string $value + * @param string|int|float|bool|array|null $expected + * @dataProvider unserializeDataProvider + */ + public function testUnserialize($value, $expected) + { + $this->assertEquals( + $expected, + $this->json->unserialize($value) + ); + } + + public function unserializeDataProvider() + { + return [ + ['""', ''], + ['"string"', 'string'], + ['null', null], + ['false', false], + ['{"a":"b","d":123}', ['a' => 'b', 'd' => 123]], + ['123', 123], + ['10.56', 10.56], + ['{}', []], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Serialize/Test/Unit/Serializer/SerializeTest.php b/lib/internal/Magento/Framework/Serialize/Test/Unit/Serializer/SerializeTest.php new file mode 100644 index 0000000000000..5d1e34a542826 --- /dev/null +++ b/lib/internal/Magento/Framework/Serialize/Test/Unit/Serializer/SerializeTest.php @@ -0,0 +1,71 @@ +serialize = $objectManager->getObject(Serialize::class); + } + + /** + * @param string|int|float|bool|array|null $value + * @param string $serializedValue + * @dataProvider serializeDataProvider + */ + public function testSerialize($value, $serializedValue) + { + $this->assertEquals($serializedValue, $this->serialize->serialize($value)); + } + + public function serializeDataProvider() + { + return [ + ['string', 's:6:"string";'], + ['', 's:0:"";'], + [10, 'i:10;'], + [10.5, 'd:10.5;'], + [null, 'N;'], + [false, 'b:0;'], + [['foo' => 'bar'], 'a:1:{s:3:"foo";s:3:"bar";}'], + ]; + } + + /** + * @param string $serializedValue + * @param string|int|float|bool|array|null $value + * @dataProvider unserializeDataProvider + */ + public function testUnserialize($serializedValue, $value) + { + $this->assertEquals($value, $this->serialize->unserialize($serializedValue)); + } + + public function unserializeDataProvider() + { + return [ + ['s:6:"string";', 'string'], + ['s:0:"";', ''], + ['i:10;', 10], + ['d:10.5;', 10.5], + ['N;', null], + ['b:0;', false], + ['a:1:{s:3:"foo";s:3:"bar";}', ['foo' => 'bar']], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Session/Config.php b/lib/internal/Magento/Framework/Session/Config.php index 2e9fa44a794a8..7c4fc08a5db9a 100644 --- a/lib/internal/Magento/Framework/Session/Config.php +++ b/lib/internal/Magento/Framework/Session/Config.php @@ -2,7 +2,7 @@ /** * Session configuration object * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Session; diff --git a/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php b/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php index f4928f392a71f..6616796dfd9f5 100644 --- a/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php +++ b/lib/internal/Magento/Framework/Session/Config/ConfigInterface.php @@ -2,7 +2,7 @@ /** * Session config interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Session\Config; diff --git a/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php b/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php index 265ef90d0873b..80dd72b5a66ff 100644 --- a/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php +++ b/lib/internal/Magento/Framework/Session/Config/Validator/CookieDomainValidator.php @@ -1,6 +1,6 @@ expireSessionCookie(); diff --git a/lib/internal/Magento/Framework/Session/SessionManagerInterface.php b/lib/internal/Magento/Framework/Session/SessionManagerInterface.php index ab6dbb225a8ff..f641027ef186a 100644 --- a/lib/internal/Magento/Framework/Session/SessionManagerInterface.php +++ b/lib/internal/Magento/Framework/Session/SessionManagerInterface.php @@ -2,7 +2,7 @@ /** * Magento session manager interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Session; diff --git a/lib/internal/Magento/Framework/Session/SidResolver.php b/lib/internal/Magento/Framework/Session/SidResolver.php index e8006d644e48c..1bf6282405be6 100644 --- a/lib/internal/Magento/Framework/Session/SidResolver.php +++ b/lib/internal/Magento/Framework/Session/SidResolver.php @@ -2,7 +2,7 @@ /** * SID resolver * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Session; diff --git a/lib/internal/Magento/Framework/Session/SidResolverInterface.php b/lib/internal/Magento/Framework/Session/SidResolverInterface.php index d60575e59fe21..8b51198b17de9 100644 --- a/lib/internal/Magento/Framework/Session/SidResolverInterface.php +++ b/lib/internal/Magento/Framework/Session/SidResolverInterface.php @@ -2,7 +2,7 @@ /** * SID resolver interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Session; diff --git a/lib/internal/Magento/Framework/Session/Storage.php b/lib/internal/Magento/Framework/Session/Storage.php index aed4c88b76936..eda48b74e2854 100644 --- a/lib/internal/Magento/Framework/Session/Storage.php +++ b/lib/internal/Magento/Framework/Session/Storage.php @@ -2,7 +2,7 @@ /** * Default session storage * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Session; diff --git a/lib/internal/Magento/Framework/Session/StorageInterface.php b/lib/internal/Magento/Framework/Session/StorageInterface.php index a842f14860b94..30d54cc151b0b 100644 --- a/lib/internal/Magento/Framework/Session/StorageInterface.php +++ b/lib/internal/Magento/Framework/Session/StorageInterface.php @@ -2,7 +2,7 @@ /** * Session storage interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Session; diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php index 1df7cfa69ca83..183aaabc12fbc 100644 --- a/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php +++ b/lib/internal/Magento/Framework/Session/Test/Unit/ConfigTest.php @@ -1,6 +1,6 @@ installationWritableDirectories[$code] = $this->directoryList->getPath($code); @@ -130,7 +131,7 @@ public function getInstallationCurrentWritableDirectories() } /** - * Check all sub-directories and files except for var/generation and var/di + * Check all sub-directories and files except for generated/code and generated/metadata * * @param string $directory * @return bool @@ -142,8 +143,8 @@ private function checkRecursiveDirectories($directory) \RecursiveIteratorIterator::CHILD_FIRST ); $noWritableFilesFolders = [ - $this->directoryList->getPath(DirectoryList::GENERATION) . '/', - $this->directoryList->getPath(DirectoryList::DI) . '/', + $this->directoryList->getPath(DirectoryList::GENERATED_CODE) . '/', + $this->directoryList->getPath(DirectoryList::GENERATED_METADATA) . '/', ]; $directoryIterator = new Filter($directoryIterator, $noWritableFilesFolders); diff --git a/lib/internal/Magento/Framework/Setup/InstallDataInterface.php b/lib/internal/Magento/Framework/Setup/InstallDataInterface.php index 24f7a18ae6986..e3f4ccf2cf375 100644 --- a/lib/internal/Magento/Framework/Setup/InstallDataInterface.php +++ b/lib/internal/Magento/Framework/Setup/InstallDataInterface.php @@ -1,6 +1,6 @@ appState->emulateAreaCode('setup', [$installer, 'install']); + $this->appState->emulateAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL, [$installer, 'install']); $this->state->setInstalled(); } catch (\Exception $e) { $this->state->setError(); diff --git a/lib/internal/Magento/Framework/Setup/SampleData/FixtureManager.php b/lib/internal/Magento/Framework/Setup/SampleData/FixtureManager.php index 51231e0529c9a..696cb53ad90c4 100644 --- a/lib/internal/Magento/Framework/Setup/SampleData/FixtureManager.php +++ b/lib/internal/Magento/Framework/Setup/SampleData/FixtureManager.php @@ -1,6 +1,6 @@ assertEquals($expected, $this->filePermissions->getInstallationWritableDirectories()); @@ -157,6 +158,7 @@ public function testGetMissingWritableDirectoriesAndPathsForInstallation() BP . '/var', BP . '/pub/media', BP . '/pub/static', + BP . '/generated' ]; $this->assertEquals( @@ -231,6 +233,11 @@ public function setUpDirectoryListInstallation() ->method('getPath') ->with(DirectoryList::STATIC_VIEW) ->will($this->returnValue(BP . '/pub/static')); + $this->directoryListMock + ->expects($this->at(4)) + ->method('getPath') + ->with(DirectoryList::GENERATED) + ->will($this->returnValue(BP . '/generated')); } public function setUpDirectoryWriteInstallation() diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php index 4ce704c3b6adf..a3728abbfbc2a 100644 --- a/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php @@ -1,6 +1,6 @@ @@ -12,4 +12,4 @@ - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/extend_data.xml b/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/extend_data.xml index c070901c5d978..fc75234d3b471 100644 --- a/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/extend_data.xml +++ b/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/extend_data.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/mixed_data.xml b/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/mixed_data.xml index 193d0c752369e..34356fdd6dbac 100644 --- a/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/mixed_data.xml +++ b/lib/internal/Magento/Framework/Simplexml/Test/Unit/_files/mixed_data.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Stdlib/ArrayManager.php b/lib/internal/Magento/Framework/Stdlib/ArrayManager.php index f8b758bb9d9df..2ee1a23ce8380 100644 --- a/lib/internal/Magento/Framework/Stdlib/ArrayManager.php +++ b/lib/internal/Magento/Framework/Stdlib/ArrayManager.php @@ -1,6 +1,6 @@ ['existing' => ['path' => 1]], 'value' => 'valuable data', 'result' => ['existing' => ['path' => 1], 'new' => ['path' => [2 => 'valuable data']]] + ], + 3 => [ + 'path' => ['new', 'path/2'], + 'data' => ['existing' => ['path' => 1]], + 'value' => 'valuable data', + 'result' => ['existing' => ['path' => 1], 'new' => ['path' => [2 => 'valuable data']]] ] ]; } @@ -178,6 +184,12 @@ public function setReplaceProvider() 'data' => ['existing' => ['path' => 1]], 'value' => 'valuable data', 'result' => ['existing' => ['path' => 1]] + ], + 3 => [ + 'path' => ['new', 'path', '2'], + 'data' => ['existing' => ['path' => 1]], + 'value' => 'valuable data', + 'result' => ['existing' => ['path' => 1]] ] ]; } @@ -228,6 +240,13 @@ public function moveDataProvider() 'data' => ['valid' => ['path' => 'value'], 'target' => ['path' => 'exists']], 'overwrite' => true, 'result' => ['valid' => [], 'target' => ['path' => 'value']] + ], + 4 => [ + 'path' => ['valid', 'path'], + 'targetPath' => 'target/path', + 'data' => ['valid' => ['path' => 'value'], 'target' => ['path' => 'exists']], + 'overwrite' => true, + 'result' => ['valid' => [], 'target' => ['path' => 'value']] ] ]; } @@ -267,7 +286,13 @@ public function mergeDataProvider() 'data' => [], 'value' => [true], 'result' => [] - ] + ], + 3 => [ + 'path' => ['0', 'path/1'], + 'data' => [['path' => [false, ['value' => false]]]], + 'value' => ['value' => true, 'new_value' => false], + 'result' => [['path' => [false, ['value' => true, 'new_value' => false]]]] + ], ]; } @@ -337,7 +362,12 @@ public function removeDataProvider() 'path' => 'invalid', 'data' => [true], 'result' => [true] - ] + ], + 3 => [ + 'path' => ['simple'], + 'data' => ['simple' => true, 'complex' => false], + 'result' => ['complex' => false] + ], ]; } @@ -550,7 +580,7 @@ public function slicePathDataProvider() 'offset' => -6, 'length' => 3, 'result' => 'path/0/goes' - ] + ], ]; } diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayUtilsTest.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayUtilsTest.php index d9786ff071c7e..cf8f821cc8684 100644 --- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayUtilsTest.php +++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/ArrayUtilsTest.php @@ -1,6 +1,6 @@ deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionFactoryMock = $this->getMockBuilder(ConnectionFactoryInterface::class) + ->getMock(); + + $this->configMock = $this->getMockBuilder(ConfigInterface::class)->getMock(); + + $this->objectManager = (new ObjectManager($this)); + $this->unit = $this->objectManager->getObject( + ResourceConnection::class, + [ + 'deploymentConfig' => $this->deploymentConfigMock, + 'connectionFactory' => $this->connectionFactoryMock, + 'config' => $this->configMock, + ] + ); + } + + public function testGetConnectionByName() + { + $this->deploymentConfigMock->expects(self::once())->method('get') + ->with(ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTIONS . '/default') + ->willReturn(['config']); + $this->connectionFactoryMock->expects(self::once())->method('create') + ->with(['config']) + ->willReturn('connection'); + + self::assertEquals('connection', $this->unit->getConnectionByName('default')); + } + + public function testGetExistingConnectionByName() + { + $unit = $this->objectManager->getObject( + ResourceConnection::class, + [ + 'deploymentConfig' => $this->deploymentConfigMock, + 'connections' => ['default_process_' . getmypid() => 'existing_connection'] + ] + ); + $this->deploymentConfigMock->expects(self::never())->method('get'); + + self::assertEquals('existing_connection', $unit->getConnectionByName('default')); + } + + public function testCloseConnection() + { + $this->configMock->expects(self::once())->method('getConnectionName')->with('default'); + + $this->unit->closeConnection('default'); + + } +} diff --git a/lib/internal/Magento/Framework/Test/Unit/App/Scope/SourceTest.php b/lib/internal/Magento/Framework/Test/Unit/App/Scope/SourceTest.php index 37c8c98805c21..f693900fa79cf 100644 --- a/lib/internal/Magento/Framework/Test/Unit/App/Scope/SourceTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/App/Scope/SourceTest.php @@ -1,6 +1,6 @@ batchSize = 10; + $this->correlationName = 'correlationName'; + $this->rangeField = 'rangeField'; + $this->rangeFieldAlias = 'rangeFieldAlias'; + + $this->selectMock = $this->getMock(Select::class, [], [], '', false, false); + $this->wrapperSelectMock = $this->getMock(Select::class, [], [], '', false, false); + $this->connectionMock = $this->getMock(AdapterInterface::class); + $this->connectionMock->expects($this->any())->method('select')->willReturn($this->wrapperSelectMock); + $this->selectMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock); + $this->connectionMock->expects($this->any())->method('quoteIdentifier')->willReturnArgument(0); + + $this->model = new BatchIterator( + $this->selectMock, + $this->batchSize, + $this->correlationName, + $this->rangeField, + $this->rangeFieldAlias + ); + } + + /** + * Test steps: + * 1. $iterator->current(); + * 2. $iterator->current(); + * 3. $iterator->key(); + * @return void + */ + public function testCurrent() + { + $filed = $this->correlationName . '.' . $this->rangeField; + + $this->selectMock->expects($this->once())->method('where')->with($filed . ' > ?', 0); + $this->selectMock->expects($this->once())->method('limit')->with($this->batchSize); + $this->selectMock->expects($this->once())->method('order')->with($filed . ' ASC'); + $this->assertEquals($this->selectMock, $this->model->current()); + $this->assertEquals($this->selectMock, $this->model->current()); + $this->assertEquals(0, $this->model->key()); + } + + /** + * SQL: select * from users + * Batch size: 10 + * IDS: [1 - 25] + * Items count: 25 + * Expected batches: [1-10, 11-20, 20-25] + * + * Test steps: + * 1. $iterator->rewind(); + * 2. $iterator->valid(); + * 3. $iterator->current(); + * 4. $iterator->key(); + * + * 1. $iterator->next() + * 2. $iterator->valid(); + * 3. $iterator->current(); + * 4. $iterator->key(); + * + * 1. $iterator->next() + * 2. $iterator->valid(); + * 3. $iterator->current(); + * 4. $iterator->key(); + * + * + * 1. $iterator->next() + * 2. $iterator->valid(); + * @return void + */ + public function testIterations() + { + $startCallIndex = 3; + $stepCall = 4; + + $this->connectionMock->expects($this->at($startCallIndex)) + ->method('fetchRow') + ->willReturn(['max' => 10, 'cnt' => 10]); + + $this->connectionMock->expects($this->at($startCallIndex += $stepCall)) + ->method('fetchRow') + ->willReturn(['max' => 20, 'cnt' => 10]); + + $this->connectionMock->expects($this->at($startCallIndex += $stepCall)) + ->method('fetchRow') + ->willReturn(['max' => 25, 'cnt' => 5]); + + $this->connectionMock->expects($this->at($startCallIndex += $stepCall)) + ->method('fetchRow') + ->willReturn(['max' => null, 'cnt' => 0]); + + /** + * Test 3 iterations + * [1-10, 11-20, 20-25] + */ + $iteration = 0; + $result = []; + foreach ($this->model as $key => $select) { + $result[] = $select; + $this->assertEquals($iteration, $key); + $iteration++; + } + $this->assertCount(3, $result); + } + + /** + * Test steps: + * 1. $iterator->next(); + * 2. $iterator->key() + * 3. $iterator->next(); + * 4. $iterator->current() + * 5. $iterator->key() + * @return void + */ + public function testNext() + { + $filed = $this->correlationName . '.' . $this->rangeField; + $this->selectMock->expects($this->at(0))->method('where')->with($filed . ' > ?', 0); + $this->selectMock->expects($this->exactly(3))->method('limit')->with($this->batchSize); + $this->selectMock->expects($this->exactly(3))->method('order')->with($filed . ' ASC'); + $this->selectMock->expects($this->at(3))->method('where')->with($filed . ' > ?', 25); + + $this->wrapperSelectMock->expects($this->exactly(3))->method('from')->with( + $this->selectMock, + [ + new \Zend_Db_Expr('MAX(' . $this->rangeFieldAlias . ') as max'), + new \Zend_Db_Expr('COUNT(*) as cnt') + ] + ); + $this->connectionMock->expects($this->exactly(3)) + ->method('fetchRow') + ->with($this->wrapperSelectMock) + ->willReturn(['max' => 25, 'cnt' => 10]); + + $this->assertEquals($this->selectMock, $this->model->next()); + $this->assertEquals(1, $this->model->key()); + + $this->assertEquals($this->selectMock, $this->model->next()); + $this->assertEquals($this->selectMock, $this->model->current()); + $this->assertEquals(2, $this->model->key()); + } +} diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php new file mode 100644 index 0000000000000..fcfaa41ffb4e6 --- /dev/null +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php @@ -0,0 +1,168 @@ +factoryMock = $this->getMock(BatchIteratorFactory::class, [], [], '', false, false); + $this->selectMock = $this->getMock(Select::class, [], [], '', false, false); + $this->iteratorMock = $this->getMock(BatchIterator::class, [], [], '', false, false); + $this->model = new Generator($this->factoryMock); + } + + /** + * Test success generate. + * @return void + */ + public function testGenerate() + { + $map = [ + [ + Select::FROM, + [ + 'cp' => ['joinType' => Select::FROM] + ] + ], + [ + Select::COLUMNS, + [ + ['cp', 'entity_id', 'product_id'] + ] + ] + ]; + $this->selectMock->expects($this->exactly(2))->method('getPart')->willReturnMap($map); + $this->factoryMock->expects($this->once())->method('create')->with( + [ + 'select' => $this->selectMock, + 'batchSize' => 100, + 'correlationName' => 'cp', + 'rangeField' => 'entity_id', + 'rangeFieldAlias' => 'product_id' + ] + )->willReturn($this->iteratorMock); + $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); + } + + /** + * Test batch generation with invalid select object. + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Select object must have correct "FROM" part + * @return void + */ + public function testGenerateWithoutFromPart() + { + $map = [ + [Select::FROM, []], + [ + Select::COLUMNS, + [ + ['cp', 'entity_id', 'product_id'] + ] + ] + ]; + $this->selectMock->expects($this->any())->method('getPart')->willReturnMap($map); + $this->factoryMock->expects($this->never())->method('create'); + $this->model->generate('entity_id', $this->selectMock, 100); + } + + /** + * Test generate batches with rangeField without alias. + * @return void + */ + public function testGenerateWithRangeFieldWithoutAlias() + { + $map = [ + [ + Select::FROM, + [ + 'cp' => ['joinType' => Select::FROM] + ] + ], + [ + Select::COLUMNS, + [ + ['cp', 'entity_id', null] + ] + ] + ]; + $this->selectMock->expects($this->exactly(2))->method('getPart')->willReturnMap($map); + $this->factoryMock->expects($this->once())->method('create')->with( + [ + 'select' => $this->selectMock, + 'batchSize' => 100, + 'correlationName' => 'cp', + 'rangeField' => 'entity_id', + 'rangeFieldAlias' => 'entity_id' + ] + )->willReturn($this->iteratorMock); + $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); + } + + /** + * Test generate batches with wild-card. + * + * @return void + */ + public function testGenerateWithInvalidWithWildcard() + { + $map = [ + [ + Select::FROM, + [ + 'cp' => ['joinType' => Select::FROM] + ] + ], + [ + Select::COLUMNS, + [ + ['cp', '*', null] + ] + ] + ]; + $this->selectMock->expects($this->exactly(2))->method('getPart')->willReturnMap($map); + $this->factoryMock->expects($this->once())->method('create')->with( + [ + 'select' => $this->selectMock, + 'batchSize' => 100, + 'correlationName' => 'cp', + 'rangeField' => 'entity_id', + 'rangeFieldAlias' => 'entity_id' + ] + )->willReturn($this->iteratorMock); + $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); + } +} diff --git a/lib/internal/Magento/Framework/Test/Unit/EscaperTest.php b/lib/internal/Magento/Framework/Test/Unit/EscaperTest.php index 7348537c32666..75e6e7892f57f 100644 --- a/lib/internal/Magento/Framework/Test/Unit/EscaperTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/EscaperTest.php @@ -1,6 +1,6 @@ _escaper = new Escaper(); + $this->escaper = new Escaper(); $this->zendEscaper = new \Magento\Framework\ZendEscaper(); + $this->loggerMock = $this->getMockForAbstractClass(\Psr\Log\LoggerInterface::class); $objectManagerHelper = new ObjectManager($this); - $objectManagerHelper->setBackwardCompatibleProperty($this->_escaper, 'escaper', $this->zendEscaper); + $objectManagerHelper->setBackwardCompatibleProperty($this->escaper, 'escaper', $this->zendEscaper); + $objectManagerHelper->setBackwardCompatibleProperty($this->escaper, 'logger', $this->loggerMock); + } + + /** + * Convert a unicode codepoint to a literal UTF-8 character + * + * @param int $codepoint Unicode codepoint in hex notation + * @return string UTF-8 literal string + */ + protected function codepointToUtf8($codepoint) + { + if ($codepoint < 0x80) { + return chr($codepoint); + } + if ($codepoint < 0x800) { + return chr($codepoint >> 6 & 0x3f | 0xc0) + . chr($codepoint & 0x3f | 0x80); + } + if ($codepoint < 0x10000) { + return chr($codepoint >> 12 & 0x0f | 0xe0) + . chr($codepoint >> 6 & 0x3f | 0x80) + . chr($codepoint & 0x3f | 0x80); + } + if ($codepoint < 0x110000) { + return chr($codepoint >> 18 & 0x07 | 0xf0) + . chr($codepoint >> 12 & 0x3f | 0x80) + . chr($codepoint >> 6 & 0x3f | 0x80) + . chr($codepoint & 0x3f | 0x80); + } + throw new \Exception('Codepoint requested outside of unicode range'); + } + + public function testEscapeJsEscapesOwaspRecommendedRanges() + { + // Exceptions to escaping ranges + $immune = [',', '.', '_']; + for ($chr = 0; $chr < 0xFF; $chr++) { + if ($chr >= 0x30 && $chr <= 0x39 + || $chr >= 0x41 && $chr <= 0x5A + || $chr >= 0x61 && $chr <= 0x7A + ) { + $literal = $this->codepointToUtf8($chr); + $this->assertEquals($literal, $this->escaper->escapeJs($literal)); + } else { + $literal = $this->codepointToUtf8($chr); + if (in_array($literal, $immune)) { + $this->assertEquals($literal, $this->escaper->escapeJs($literal)); + } else { + $this->assertNotEquals( + $literal, + $this->escaper->escapeJs($literal), + $literal . ' should be escaped!' + ); + } + } + } + } + + /** + * @param string $data + * @param string $expected + * @dataProvider escapeJsDataProvider + */ + public function testEscapeJs($data, $expected) + { + $this->assertEquals($expected, $this->escaper->escapeJs($data)); + } + + public function escapeJsDataProvider() + { + return [ + 'zero length string' => ['', ''], + 'only digits' => ['123', '123'], + '<' => ['<', '\u003C'], + '>' => ['>', '\\u003E'], + '\'' => ['\'', '\\u0027'], + '"' => ['"', '\\u0022'], + '&' => ['&', '\\u0026'], + 'Characters beyond ASCII value 255 to unicode escape' => ['Ā', '\\u0100'], + 'Characters beyond Unicode BMP to unicode escape' => ["\xF0\x90\x80\x80", '\\uD800DC00'], + /* Immune chars excluded */ + ',' => [',', ','], + '.' => ['.', '.'], + '_' => ['_', '_'], + /* Basic alnums exluded */ + 'a' => ['a', 'a'], + 'A' => ['A', 'A'], + 'z' => ['z', 'z'], + 'Z' => ['Z', 'Z'], + '0' => ['0', '0'], + '9' => ['9', '9'], + /* Basic control characters and null */ + "\r" => ["\r", '\\u000D'], + "\n" => ["\n", '\\u000A'], + "\t" => ["\t", '\\u0009'], + "\0" => ["\0", '\\u0000'], + 'Encode spaces for quoteless attribute protection' => [' ', '\\u0020'], + ]; } /** * @covers \Magento\Framework\Escaper::escapeHtml * @dataProvider escapeHtmlDataProvider */ - public function testEscapeHtml($data, $expected, $allowedTags = null) + public function testEscapeHtml($data, $expected, $allowedTags = []) { - $actual = $this->_escaper->escapeHtml($data, $allowedTags); + $actual = $this->escaper->escapeHtml($data, $allowedTags); + $this->assertEquals($expected, $actual); + } + + /** + * @covers \Magento\Framework\Escaper::escapeHtml + * @dataProvider escapeHtmlInvalidDataProvider + */ + public function testEscapeHtmlWithInvalidData($data, $expected, $allowedTags = []) + { + $this->loggerMock->expects($this->once()) + ->method('critical'); + $actual = $this->escaper->escapeHtml($data, $allowedTags); $this->assertEquals($expected, $actual); } @@ -47,22 +163,95 @@ public function testEscapeHtml($data, $expected, $allowedTags = null) public function escapeHtmlDataProvider() { return [ - 'array data' => [ + 'array -> [text with no tags, text with no allowed tags]' => [ 'data' => ['one', 'three'], 'expected' => ['one', '<two>three</two>'], - null, ], - 'string data conversion' => [ - 'data' => 'three', - 'expected' => '<two>three</two>', - null, + 'text with special characters' => [ + 'data' => '&<>"\'&<>"' ', + 'expected' => '&<>"'&<>"' ' ], - 'string data no conversion' => ['data' => 'one', 'expected' => 'one'], - 'string data with allowed tags' => [ - 'data' => 'some text in tags', - 'expected' => 'some text in tags', + 'text with multiple allowed tags, includes self closing tag' => [ + 'data' => 'some text in tags
    ', + 'expected' => 'some text in tags
    ', + 'allowedTags' => ['span', 'br'], + ], + 'text with multiple allowed tags and allowed attribute in double quotes' => [ + 'data' => 'Only 2 in stock', + 'expected' => 'Only 2 in stock', 'allowedTags' => ['span', 'b'], - ] + ], + 'text with multiple allowed tags and allowed attribute in single quotes' => [ + 'data' => 'Only 2 in stock', + 'expected' => 'Only 2 in stock', + 'allowedTags' => ['span', 'b'], + ], + 'text with multiple allowed tags with allowed attribute' => [ + 'data' => 'Only registered users can write reviews. Please Sign in or ' + . 'create an account', + 'expected' => 'Only registered users can write reviews. Please Sign in or ' + . 'create an account', + 'allowedTags' => ['a'], + ], + 'text with not allowed attribute in single quotes' => [ + 'data' => 'Only 2 in stock', + 'expected' => 'Only 2 in stock', + 'allowedTags' => ['span', 'b'], + ], + 'text with allowed and not allowed tags' => [ + 'data' => 'Only registered users can write reviews. Please Sign inthree ' + . 'or create an account', + 'expected' => 'Only registered users can write reviews. Please Sign inthree or ' + . 'create an account', + 'allowedTags' => ['a'], + ], + 'text with allowed and not allowed tags, with allowed and not allowed attributes' => [ + 'data' => 'Some test text in span tag text in strong tag ' + . 'Click here', + 'expected' => 'Some test text in span tag text in strong tag ' + . 'Click herealert(1)', + 'allowedTags' => ['a', 'span'], + ], + 'text with html comment' => [ + 'data' => 'Only 2 in stock ', + 'expected' => 'Only 2 in stock ', + 'allowedTags' => ['span', 'b'], + ], + 'text with non ascii characters' => [ + 'data' => ['абвгд', 'مثال', '幸福'], + 'expected' => ['абвгд', 'مثال', '幸福'], + 'allowedTags' => [], + ], + 'html and body tags' => [ + 'data' => 'String', + 'expected' => 'String', + 'allowedTags' => ['span'], + ], + 'invalid tag' => [ + 'data' => ' some text', + 'expected' => ' some text', + 'allowedTags' => ['span'], + ], + ]; + } + + /** + * @return array + */ + public function escapeHtmlInvalidDataProvider() + { + return [ + 'text with allowed script tag' => [ + 'data' => '', + 'expected' => 'some text in tags', + 'allowedTags' => ['span', 'script'], + ], + 'text with invalid html' => [ + 'data' => 'n id="id1">Some string', + 'expected' => 'n id="id1">Some string', + 'allowedTags' => ['span'], + ], ]; } @@ -73,8 +262,8 @@ public function testEscapeUrl() { $data = 'http://example.com/search?term=this+%26+that&view=list'; $expected = 'http://example.com/search?term=this+%26+that&view=list'; - $this->assertEquals($expected, $this->_escaper->escapeUrl($data)); - $this->assertEquals($expected, $this->_escaper->escapeUrl($expected)); + $this->assertEquals($expected, $this->escaper->escapeUrl($data)); + $this->assertEquals($expected, $this->escaper->escapeUrl($expected)); } /** @@ -84,8 +273,8 @@ public function testEscapeJsQuote() { $data = ["Don't do that.", 'lost_key' => "Can't do that."]; $expected = ["Don\\'t do that.", "Can\\'t do that."]; - $this->assertEquals($expected, $this->_escaper->escapeJsQuote($data)); - $this->assertEquals($expected[0], $this->_escaper->escapeJsQuote($data[0])); + $this->assertEquals($expected, $this->escaper->escapeJsQuote($data)); + $this->assertEquals($expected[0], $this->escaper->escapeJsQuote($data[0])); } /** @@ -98,8 +287,8 @@ public function testEscapeQuote() "Text with 'single' and "double" quotes", "Text with \\'single\\' and \\"double\\" quotes", ]; - $this->assertEquals($expected[0], $this->_escaper->escapeQuote($data)); - $this->assertEquals($expected[1], $this->_escaper->escapeQuote($data, true)); + $this->assertEquals($expected[0], $this->escaper->escapeQuote($data)); + $this->assertEquals($expected[1], $this->escaper->escapeQuote($data, true)); } /** @@ -110,7 +299,7 @@ public function testEscapeQuote() */ public function testEscapeXssInUrl($input, $expected) { - $this->assertEquals($expected, $this->_escaper->escapeXssInUrl($input)); + $this->assertEquals($expected, $this->escaper->escapeXssInUrl($input)); } /** diff --git a/lib/internal/Magento/Framework/Test/Unit/EventFactoryTest.php b/lib/internal/Magento/Framework/Test/Unit/EventFactoryTest.php index 5b8af515ab86a..e5b06e5a3a79b 100644 --- a/lib/internal/Magento/Framework/Test/Unit/EventFactoryTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/EventFactoryTest.php @@ -1,6 +1,6 @@ 'synchronize']; @@ -71,13 +81,22 @@ protected function createInstance(array $data = []) $resourceCollection = $this->getMockBuilder(\Magento\Framework\Data\Collection\AbstractDb::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); + $this->json = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->setMethods(null) + ->getMock(); + + $this->serialize = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Serialize::class) + ->setMethods(null) + ->getMock(); $this->flag = new \Magento\Framework\Flag( $context, $registry, $resource, $resourceCollection, - $data + $data, + $this->json, + $this->serialize ); } @@ -94,7 +113,17 @@ public function testConstruct() $this->assertEquals($flagCode, $this->flag->getFlagCode()); } - public function testGetFlagData() + public function testGetFlagDataJson() + { + $result = $this->flag->getFlagData(); + $this->assertNull($result); + $flagData = json_encode('data'); + $this->flag->setData('flag_data', $flagData); + $result = $this->flag->getFlagData(); + $this->assertEquals(json_decode($flagData), $result); + } + + public function testGetFlagDataSerialized() { $result = $this->flag->getFlagData(); $this->assertNull($result); @@ -108,7 +137,7 @@ public function testSetFlagData() { $flagData = 'data'; $this->flag->setFlagData($flagData); - $result = unserialize($this->flag->getData('flag_data')); + $result = json_decode($this->flag->getData('flag_data')); $this->assertEquals($flagData, $result); } diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/InterceptorTest.php b/lib/internal/Magento/Framework/Test/Unit/Interception/InterceptorTest.php index 7b3624c501d8d..0da6ef45e3b2a 100644 --- a/lib/internal/Magento/Framework/Test/Unit/Interception/InterceptorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/Interception/InterceptorTest.php @@ -1,6 +1,6 @@ viewDesign = $this->getMock(\Magento\Framework\View\DesignInterface::class, [], [], '', false); $this->cache = $this->getMock(\Magento\Framework\Cache\FrontendInterface::class, [], [], '', false); $this->viewFileSystem = $this->getMock(\Magento\Framework\View\FileSystem::class, [], [], '', false); @@ -104,6 +106,21 @@ protected function setUp() $this->csvParser, $this->packDictionary ); + + $serializerMock = $this->getMock(SerializerInterface::class); + $serializerMock->method('serialize') + ->willReturnCallback(function ($data) { + return json_encode($data); + }); + $serializerMock->method('unserialize') + ->willReturnCallback(function ($string) { + return json_decode($string, true); + }); + $objectManager->setBackwardCompatibleProperty( + $this->translate, + 'serializer', + $serializerMock + ); } /** @@ -119,7 +136,7 @@ public function testLoadData($area, $forceReload, $cachedData) $this->cache->expects($this->exactly($forceReload ? 0 : 1)) ->method('load') - ->will($this->returnValue(serialize($cachedData))); + ->will($this->returnValue(json_encode($cachedData))); if (!$forceReload && $cachedData !== false) { $this->translate->loadData($area, $forceReload); @@ -222,7 +239,7 @@ public function testGetData($data, $result) { $this->cache->expects($this->once()) ->method('load') - ->will($this->returnValue(serialize($data))); + ->will($this->returnValue(json_encode($data))); $this->expectsSetConfig('themeId'); $this->translate->loadData('frontend'); $this->assertEquals($result, $this->translate->getData()); diff --git a/lib/internal/Magento/Framework/Test/Unit/UrlTest.php b/lib/internal/Magento/Framework/Test/Unit/UrlTest.php index 36fce179395b5..cfb4fb884accb 100644 --- a/lib/internal/Magento/Framework/Test/Unit/UrlTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/UrlTest.php @@ -1,12 +1,13 @@ routeParamsResolverMock = $this->getMock( @@ -549,18 +555,17 @@ public function testAddSessionParam() /** * @param bool $result - * @param string $baseUrl * @param string $referrer * @dataProvider isOwnOriginUrlDataProvider */ - public function testIsOwnOriginUrl($result, $baseUrl, $referrer) + public function testIsOwnOriginUrl($result, $referrer) { $requestMock = $this->getRequestMock(); - $model = $this->getUrlModel(['scopeResolver' => $this->scopeResolverMock, 'request' => $requestMock]); + $this->hostChecker = $this->getMockBuilder(HostChecker::class) + ->disableOriginalConstructor()->getMock(); + $this->hostChecker->expects($this->once())->method('isOwnOrigin')->with($referrer)->willReturn($result); + $model = $this->getUrlModel(['hostChecker' => $this->hostChecker, 'request' => $requestMock]); - $this->scopeMock->expects($this->any())->method('getBaseUrl')->will($this->returnValue($baseUrl)); - $this->scopeResolverMock->expects($this->any())->method('getScopes') - ->will($this->returnValue([$this->scopeMock])); $requestMock->expects($this->once())->method('getServer')->with('HTTP_REFERER') ->will($this->returnValue($referrer)); @@ -570,8 +575,8 @@ public function testIsOwnOriginUrl($result, $baseUrl, $referrer) public function isOwnOriginUrlDataProvider() { return [ - 'is origin url' => [true, 'http://localhost/', 'http://localhost/'], - 'is not origin url' => [false, 'http://localhost/', 'http://example.com/'], + 'is origin url' => [true, 'http://localhost/'], + 'is not origin url' => [false, 'http://example.com/'], ]; } diff --git a/lib/internal/Magento/Framework/Test/Unit/UtilTest.php b/lib/internal/Magento/Framework/Test/Unit/UtilTest.php index 8ca76e375b8b7..a356349d85684 100644 --- a/lib/internal/Magento/Framework/Test/Unit/UtilTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/UtilTest.php @@ -2,7 +2,7 @@ /** * Collection of various useful functions * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Test\Unit; diff --git a/lib/internal/Magento/Framework/Test/Unit/ValidatorFactoryTest.php b/lib/internal/Magento/Framework/Test/Unit/ValidatorFactoryTest.php index 2c8dca01988e7..9474e72651fce 100644 --- a/lib/internal/Magento/Framework/Test/Unit/ValidatorFactoryTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/ValidatorFactoryTest.php @@ -2,7 +2,7 @@ /** * Unit test for Magento\Framework\ValidatorFactory * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Test/Unit/ValidatorTest.php b/lib/internal/Magento/Framework/Test/Unit/ValidatorTest.php index af48d24de887d..6745f4e6c0544 100644 --- a/lib/internal/Magento/Framework/Test/Unit/ValidatorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/ValidatorTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xml b/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xml index 8eee79f23b73e..2afb2f8379e9b 100644 --- a/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xml +++ b/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xsd b/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xsd index aec264cdb4173..4640abfcf07e8 100644 --- a/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xsd +++ b/lib/internal/Magento/Framework/TestFramework/Test/Unit/Unit/Utility/_files/valid.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/TestFramework/Unit/AbstractFactoryTestCase.php b/lib/internal/Magento/Framework/TestFramework/Unit/AbstractFactoryTestCase.php index 1efff6d6761dd..87c0f48eb7c82 100644 --- a/lib/internal/Magento/Framework/TestFramework/Unit/AbstractFactoryTestCase.php +++ b/lib/internal/Magento/Framework/TestFramework/Unit/AbstractFactoryTestCase.php @@ -2,7 +2,7 @@ /** * Framework for unit tests containing helper methods * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. * * Number of fields is necessary because of the number of fields used by multiple layers diff --git a/lib/internal/Magento/Framework/TestFramework/Unit/Autoloader/ExtensionGeneratorAutoloader.php b/lib/internal/Magento/Framework/TestFramework/Unit/Autoloader/ExtensionGeneratorAutoloader.php index 4e0fcac1fdff2..9f8cb85b76ecd 100644 --- a/lib/internal/Magento/Framework/TestFramework/Unit/Autoloader/ExtensionGeneratorAutoloader.php +++ b/lib/internal/Magento/Framework/TestFramework/Unit/Autoloader/ExtensionGeneratorAutoloader.php @@ -1,6 +1,6 @@ getProperty($propertyName); $reflectionProperty->setAccessible(true); $reflectionProperty->setValue($object, $propertyValue); diff --git a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ProxyTesting.php b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ProxyTesting.php index 85d21ed2d1a75..077dc7e2bea6f 100644 --- a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ProxyTesting.php +++ b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ProxyTesting.php @@ -1,6 +1,6 @@ _cache->load($this->getCacheId()); if ($data) { - $data = unserialize($data); + $data = $this->getSerializer()->unserialize($data); } return $data; } @@ -486,7 +491,22 @@ protected function _loadCache() */ protected function _saveCache() { - $this->_cache->save(serialize($this->getData()), $this->getCacheId(true), [], false); + $this->_cache->save($this->getSerializer()->serialize($this->getData()), $this->getCacheId(true), [], false); return $this; } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(Serialize\SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/Translate/AbstractAdapter.php b/lib/internal/Magento/Framework/Translate/AbstractAdapter.php index 2f0ceb7735eae..cd43d61074f52 100644 --- a/lib/internal/Magento/Framework/Translate/AbstractAdapter.php +++ b/lib/internal/Magento/Framework/Translate/AbstractAdapter.php @@ -1,6 +1,6 @@ _request = $request; $this->_routeConfig = $routeConfig; @@ -218,6 +227,8 @@ public function __construct( $this->_scopeConfig = $scopeConfig; $this->routeParamsPreprocessor = $routeParamsPreprocessor; $this->_scopeType = $scopeType; + $this->hostChecker = $hostChecker ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(HostChecker::class); parent::__construct($data); } @@ -1086,17 +1097,7 @@ public function useSessionIdForUrl($secure = false) */ public function isOwnOriginUrl() { - $scopeDomains = []; - $referer = parse_url($this->_request->getServer('HTTP_REFERER'), PHP_URL_HOST); - foreach ($this->_scopeResolver->getScopes() as $scope) { - $scopeDomains[] = parse_url($scope->getBaseUrl(), PHP_URL_HOST); - $scopeDomains[] = parse_url($scope->getBaseUrl(UrlInterface::URL_TYPE_LINK, true), PHP_URL_HOST); - } - $scopeDomains = array_unique($scopeDomains); - if (empty($referer) || in_array($referer, $scopeDomains)) { - return true; - } - return false; + return $this->hostChecker->isOwnOrigin($this->_request->getServer('HTTP_REFERER')); } /** @@ -1163,7 +1164,7 @@ protected function getRouteParamsResolver() private function getUrlModifier() { if ($this->urlModifier === null) { - $this->urlModifier = \Magento\Framework\App\ObjectManager::getInstance()->get( + $this->urlModifier = \Magento\Framework\App\ObjectManager::getInstance()->get( \Magento\Framework\Url\ModifierInterface::class ); } diff --git a/lib/internal/Magento/Framework/Url/Decoder.php b/lib/internal/Magento/Framework/Url/Decoder.php index d60611062d076..06a865db0079f 100644 --- a/lib/internal/Magento/Framework/Url/Decoder.php +++ b/lib/internal/Magento/Framework/Url/Decoder.php @@ -1,6 +1,6 @@ scopeResolver = $scopeResolver; + } + + /** + * Check if provided URL is one of the domain URLs assigned to scopes + * + * @param string $url + * @return bool + */ + public function isOwnOrigin($url) + { + $scopeHostNames = []; + $hostName = parse_url($url, PHP_URL_HOST); + if (empty($hostName)) { + return true; + } + foreach ($this->scopeResolver->getScopes() as $scope) { + $scopeHostNames[] = parse_url($scope->getBaseUrl(), PHP_URL_HOST); + $scopeHostNames[] = parse_url($scope->getBaseUrl(UrlInterface::URL_TYPE_LINK, true), PHP_URL_HOST); + } + $scopeHostNames = array_unique($scopeHostNames); + return in_array($hostName, $scopeHostNames); + } +} diff --git a/lib/internal/Magento/Framework/Url/ModifierComposite.php b/lib/internal/Magento/Framework/Url/ModifierComposite.php index 044faf23182de..1f301f4ae5e83 100644 --- a/lib/internal/Magento/Framework/Url/ModifierComposite.php +++ b/lib/internal/Magento/Framework/Url/ModifierComposite.php @@ -1,6 +1,6 @@ scopeResolver = $this->getMockBuilder( + \Magento\Framework\Url\ScopeResolverInterface::class + )->getMock(); + + $objectManager = new ObjectManager($this); + $this->object = $objectManager->getObject( + \Magento\Framework\Url\HostChecker::class, + [ + 'scopeResolver' => $this->scopeResolver + ] + ); + } + + /** + * @dataProvider isOwnOriginDataProvider + * @param string $url + * @param boolean $result + */ + public function testIsOwnOrigin($url, $result) + { + $scopes[0] = $this->getMockBuilder(\Magento\Framework\Url\ScopeInterface::class)->getMock(); + $scopes[0]->expects($this->any())->method('getBaseUrl')->willReturn('http://www.example.com'); + $scopes[1] = $this->getMockBuilder(\Magento\Framework\Url\ScopeInterface::class)->getMock(); + $scopes[1]->expects($this->any())->method('getBaseUrl')->willReturn('https://www.example2.com'); + + $this->scopeResolver->expects($this->atLeastOnce())->method('getScopes')->willReturn($scopes); + + $this->assertEquals($result, $this->object->isOwnOrigin($url)); + } + + /** + * @return array + */ + public function isOwnOriginDataProvider() + { + return [ + ['http://www.example.com/some/page/', true], + ['http://www.test.com/other/page/', false], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Url/Test/Unit/QueryParamsResolverTest.php b/lib/internal/Magento/Framework/Url/Test/Unit/QueryParamsResolverTest.php index ea94ea270eb17..ca53f9ef2273a 100644 --- a/lib/internal/Magento/Framework/Url/Test/Unit/QueryParamsResolverTest.php +++ b/lib/internal/Magento/Framework/Url/Test/Unit/QueryParamsResolverTest.php @@ -1,6 +1,6 @@ listOfProtocols = $listOfProtocols; + } + } + + /** + * Validate URI + * + * @param string $value + * @return bool + */ + public function isValid($value) + { + $uri = new Uri($value); + $isValid = in_array( + strtolower($uri->getScheme()), + $this->listOfProtocols + ); + if (!$isValid) { + $this->_addMessages(["Protocol isn't allowed"]); + } + return $isValid; + } +} diff --git a/lib/internal/Magento/Framework/Validator/Alnum.php b/lib/internal/Magento/Framework/Validator/Alnum.php index da0bc22ebc708..bc3470b54c3db 100644 --- a/lib/internal/Magento/Framework/Validator/Alnum.php +++ b/lib/internal/Magento/Framework/Validator/Alnum.php @@ -2,7 +2,7 @@ /** * Alphanumerical validator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator; diff --git a/lib/internal/Magento/Framework/Validator/Builder.php b/lib/internal/Magento/Framework/Validator/Builder.php index e31a2c86d9238..fe5465124d878 100644 --- a/lib/internal/Magento/Framework/Validator/Builder.php +++ b/lib/internal/Magento/Framework/Validator/Builder.php @@ -2,7 +2,7 @@ /** * Magento Validator Builder * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Validator/Config.php b/lib/internal/Magento/Framework/Validator/Config.php index dc0d6a6259db2..7860fc811220c 100644 --- a/lib/internal/Magento/Framework/Validator/Config.php +++ b/lib/internal/Magento/Framework/Validator/Config.php @@ -2,7 +2,7 @@ /** * Validation configuration files handler * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator; diff --git a/lib/internal/Magento/Framework/Validator/Constraint.php b/lib/internal/Magento/Framework/Validator/Constraint.php index 3e40085397121..af87ba8e9029d 100644 --- a/lib/internal/Magento/Framework/Validator/Constraint.php +++ b/lib/internal/Magento/Framework/Validator/Constraint.php @@ -2,7 +2,7 @@ /** * Validator constraint delegates validation to wrapped validator. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator; diff --git a/lib/internal/Magento/Framework/Validator/Constraint/Option.php b/lib/internal/Magento/Framework/Validator/Constraint/Option.php index 2ce72ca0c62a2..55988c73c3c79 100644 --- a/lib/internal/Magento/Framework/Validator/Constraint/Option.php +++ b/lib/internal/Magento/Framework/Validator/Constraint/Option.php @@ -2,7 +2,7 @@ /** * Constraint option * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator\Constraint; diff --git a/lib/internal/Magento/Framework/Validator/Constraint/Option/Callback.php b/lib/internal/Magento/Framework/Validator/Constraint/Option/Callback.php index 201aac589647a..4b704902af897 100644 --- a/lib/internal/Magento/Framework/Validator/Constraint/Option/Callback.php +++ b/lib/internal/Magento/Framework/Validator/Constraint/Option/Callback.php @@ -2,7 +2,7 @@ /** * Constraint callback option * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator\Constraint\Option; diff --git a/lib/internal/Magento/Framework/Validator/Constraint/OptionInterface.php b/lib/internal/Magento/Framework/Validator/Constraint/OptionInterface.php index 2b63986c82e53..1c94a804b579a 100644 --- a/lib/internal/Magento/Framework/Validator/Constraint/OptionInterface.php +++ b/lib/internal/Magento/Framework/Validator/Constraint/OptionInterface.php @@ -2,7 +2,7 @@ /** * Validator Constraint Option interface * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator\Constraint; diff --git a/lib/internal/Magento/Framework/Validator/Constraint/Property.php b/lib/internal/Magento/Framework/Validator/Constraint/Property.php index c40e3c1237e64..8178445796f50 100644 --- a/lib/internal/Magento/Framework/Validator/Constraint/Property.php +++ b/lib/internal/Magento/Framework/Validator/Constraint/Property.php @@ -2,7 +2,7 @@ /** * Validator constraint delegates validation of value's property to wrapped validator. * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/lib/internal/Magento/Framework/Validator/ConstraintFactory.php b/lib/internal/Magento/Framework/Validator/ConstraintFactory.php index 1077f21bfa2bd..dd56b49efc5dd 100644 --- a/lib/internal/Magento/Framework/Validator/ConstraintFactory.php +++ b/lib/internal/Magento/Framework/Validator/ConstraintFactory.php @@ -1,6 +1,6 @@ _configFiles = $this->cache->load(self::CACHE_KEY); if (!$this->_configFiles) { $this->_configFiles = $this->moduleReader->getConfigurationFiles('validation.xml'); - $this->cache->save(serialize($this->_configFiles), self::CACHE_KEY); + $this->cache->save($this->getSerializer()->serialize($this->_configFiles->toArray()), self::CACHE_KEY); } else { - $this->_configFiles = unserialize($this->_configFiles); + $filesArray = $this->getSerializer()->unserialize($this->_configFiles); + $this->_configFiles = $this->getFileIteratorFactory()->create(array_keys($filesArray)); } } } @@ -109,7 +120,7 @@ public function getValidatorConfig() { $this->_initializeConfigList(); $this->_initializeDefaultTranslator(); - return $this->_objectManager->create( + return $this->_objectManager->create( \Magento\Framework\Validator\Config::class, ['configFiles' => $this->_configFiles]); } @@ -140,4 +151,33 @@ public function createValidator($entityName, $groupName, array $builderConfig = $this->_initializeDefaultTranslator(); return $this->getValidatorConfig()->createValidator($entityName, $groupName, $builderConfig); } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = $this->_objectManager->get(\Magento\Framework\Serialize\SerializerInterface::class); + } + return $this->serializer; + } + + /** + * Get file iterator factory + * + * @return \Magento\Framework\Config\FileIteratorFactory + * @deprecated + */ + private function getFileIteratorFactory() + { + if ($this->fileIteratorFactory === null) { + $this->fileIteratorFactory = $this->_objectManager + ->get(\Magento\Framework\Config\FileIteratorFactory::class); + } + return $this->fileIteratorFactory; + } } diff --git a/lib/internal/Magento/Framework/Validator/File/Extension.php b/lib/internal/Magento/Framework/Validator/File/Extension.php index dfc81aa1fd751..727cfbbf3ebfc 100644 --- a/lib/internal/Magento/Framework/Validator/File/Extension.php +++ b/lib/internal/Magento/Framework/Validator/File/Extension.php @@ -2,7 +2,7 @@ /** * Validator for the file extension of a file * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator\File; diff --git a/lib/internal/Magento/Framework/Validator/File/ImageSize.php b/lib/internal/Magento/Framework/Validator/File/ImageSize.php index 957190a3b5f27..e81a4277400eb 100644 --- a/lib/internal/Magento/Framework/Validator/File/ImageSize.php +++ b/lib/internal/Magento/Framework/Validator/File/ImageSize.php @@ -2,7 +2,7 @@ /** * Validator for the image size of a image file * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator\File; diff --git a/lib/internal/Magento/Framework/Validator/File/IsImage.php b/lib/internal/Magento/Framework/Validator/File/IsImage.php index 8af98b562a62b..f1c829bbe26bf 100644 --- a/lib/internal/Magento/Framework/Validator/File/IsImage.php +++ b/lib/internal/Magento/Framework/Validator/File/IsImage.php @@ -2,7 +2,7 @@ /** * Validator which checks if the file is image * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator\File; diff --git a/lib/internal/Magento/Framework/Validator/File/Size.php b/lib/internal/Magento/Framework/Validator/File/Size.php index a4a058a35294f..e438e9b892b5a 100644 --- a/lib/internal/Magento/Framework/Validator/File/Size.php +++ b/lib/internal/Magento/Framework/Validator/File/Size.php @@ -2,7 +2,7 @@ /** * Validator for the maximum size of a file up to a max of 2GB * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator\File; diff --git a/lib/internal/Magento/Framework/Validator/FloatUtils.php b/lib/internal/Magento/Framework/Validator/FloatUtils.php index 94b151ce7c887..4588731f0f48e 100644 --- a/lib/internal/Magento/Framework/Validator/FloatUtils.php +++ b/lib/internal/Magento/Framework/Validator/FloatUtils.php @@ -2,7 +2,7 @@ /** * Float validator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator; diff --git a/lib/internal/Magento/Framework/Validator/IntUtils.php b/lib/internal/Magento/Framework/Validator/IntUtils.php index b37b706686d81..2a821c8652233 100644 --- a/lib/internal/Magento/Framework/Validator/IntUtils.php +++ b/lib/internal/Magento/Framework/Validator/IntUtils.php @@ -2,7 +2,7 @@ /** * Integer validator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator; diff --git a/lib/internal/Magento/Framework/Validator/Ip.php b/lib/internal/Magento/Framework/Validator/Ip.php index d01b6adcc956c..820960b9173e4 100644 --- a/lib/internal/Magento/Framework/Validator/Ip.php +++ b/lib/internal/Magento/Framework/Validator/Ip.php @@ -2,7 +2,7 @@ /** * Ip validator * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\Validator; diff --git a/lib/internal/Magento/Framework/Validator/Locale.php b/lib/internal/Magento/Framework/Validator/Locale.php index 2717a97a47fe5..f38b3db3ece1c 100644 --- a/lib/internal/Magento/Framework/Validator/Locale.php +++ b/lib/internal/Magento/Framework/Validator/Locale.php @@ -1,6 +1,6 @@ _defaultTranslator = \Magento\Framework\Validator\AbstractValidator::getDefaultTranslator(); - $this->_objectManager = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); - $this->_validatorConfig = $this->getMockBuilder( - \Magento\Framework\Validator\Config::class - )->setMethods( - ['createValidatorBuilder', 'createValidator'] - )->disableOriginalConstructor()->getMock(); - - $this->_objectManager->expects( - $this->at(0) - )->method( - 'create' - )->with( - \Magento\Framework\Translate\Adapter::class - )->will( - $this->returnValue(new \Magento\Framework\Translate\Adapter()) - ); + $this->defaultTranslator = \Magento\Framework\Validator\AbstractValidator::getDefaultTranslator(); - $this->_objectManager->expects( - $this->at(1) - )->method( - 'create' - )->with( + $this->objectManagerMock = $this->getMock(\Magento\Framework\ObjectManagerInterface::class); + $this->validatorConfigMock = $this->getMock( \Magento\Framework\Validator\Config::class, - ['configFiles' => ['/tmp/moduleOne/etc/validation.xml']] - )->will( - $this->returnValue($this->_validatorConfig) + ['createValidatorBuilder', 'createValidator'], + [], + '', + false ); - - // Config mock - $this->_config = $this->getMockBuilder( - \Magento\Framework\Module\Dir\Reader::class - )->setMethods( - ['getConfigurationFiles'] - )->disableOriginalConstructor()->getMock(); - $this->_config->expects( - $this->once() - )->method( - 'getConfigurationFiles' - )->with( - 'validation.xml' - )->will( - $this->returnValue(['/tmp/moduleOne/etc/validation.xml']) + $translateAdapterMock = $this->getMock(\Magento\Framework\Translate\Adapter::class, [], [], '', false); + $this->objectManagerMock->expects($this->at(0)) + ->method('create') + ->with(\Magento\Framework\Translate\Adapter::class) + ->willReturn($translateAdapterMock); + $this->fileIteratorMock = $this->getMock( + \Magento\Framework\Config\FileIterator::class, + [], + [], + '', + false + ); + $this->objectManagerMock->expects($this->at(1)) + ->method('create') + ->with( + \Magento\Framework\Validator\Config::class, + ['configFiles' => $this->fileIteratorMock] + ) + ->willReturn($this->validatorConfigMock); + $this->readerMock = $this->getMock( + \Magento\Framework\Module\Dir\Reader::class, + ['getConfigurationFiles'], + [], + '', + false ); + $this->cacheMock = $this->getMock(\Magento\Framework\Cache\FrontendInterface::class); - // Translate adapter mock - $this->_translateAdapter = $this->getMockBuilder( - \Magento\Framework\TranslateInterface::class - )->disableOriginalConstructor()->getMock(); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->factory = $objectManager->getObject( + \Magento\Framework\Validator\Factory::class, + [ + 'objectManager' => $this->objectManagerMock, + 'moduleReader' => $this->readerMock, + 'cache' => $this->cacheMock + ] + ); - $this->cache = $this->getMockBuilder(\Magento\Framework\Cache\FrontendInterface::class) - ->getMockForAbstractClass(); + $this->serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); + $this->fileIteratorFactoryMock = $this->getMock( + \Magento\Framework\Config\FileIteratorFactory::class, + [], + [], + '', + false + ); + $objectManager->setBackwardCompatibleProperty( + $this->factory, + 'serializer', + $this->serializerMock + ); + $objectManager->setBackwardCompatibleProperty( + $this->factory, + 'fileIteratorFactory', + $this->fileIteratorFactoryMock + ); } /** @@ -100,87 +141,103 @@ protected function setUp() */ protected function tearDown() { - \Magento\Framework\Validator\AbstractValidator::setDefaultTranslator($this->_defaultTranslator); - unset($this->_defaultTranslator); + \Magento\Framework\Validator\AbstractValidator::setDefaultTranslator($this->defaultTranslator); + unset($this->defaultTranslator); } - /** - * Test getValidatorConfig created correct validator config. Check that validator translator was initialized. - */ public function testGetValidatorConfig() { - $factory = new \Magento\Framework\Validator\Factory( - $this->_objectManager, - $this->_config, - $this->cache - ); - $actualConfig = $factory->getValidatorConfig(); + $this->readerMock->method('getConfigurationFiles') + ->with('validation.xml') + ->willReturn($this->fileIteratorMock); + $this->fileIteratorMock->method('toArray') + ->willReturn($this->data); + $actualConfig = $this->factory->getValidatorConfig(); $this->assertInstanceOf( \Magento\Framework\Validator\Config::class, $actualConfig, 'Object of incorrect type was created' ); - - // Check that validator translator was correctly instantiated - $validatorTranslator = \Magento\Framework\Validator\AbstractValidator::getDefaultTranslator(); $this->assertInstanceOf( \Magento\Framework\Translate\Adapter::class, - $validatorTranslator, + \Magento\Framework\Validator\AbstractValidator::getDefaultTranslator(), 'Default validator translate adapter was not set correctly' ); } - /** - * Test createValidatorBuilder call - */ + public function testGetValidatorConfigCacheNotExist() + { + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn(false); + $this->readerMock->expects($this->once()) + ->method('getConfigurationFiles') + ->willReturn($this->fileIteratorMock); + $this->fileIteratorMock->method('toArray') + ->willReturn($this->data); + $this->cacheMock->expects($this->once()) + ->method('save') + ->with($this->jsonString); + $this->serializerMock->expects($this->once()) + ->method('serialize') + ->with($this->data) + ->willReturn($this->jsonString); + $this->factory->getValidatorConfig(); + $this->factory->getValidatorConfig(); + } + + public function testGetValidatorConfigCacheExist() + { + $this->cacheMock->expects($this->once()) + ->method('load') + ->willReturn($this->jsonString); + $this->readerMock->expects($this->never()) + ->method('getConfigurationFiles'); + $this->cacheMock->expects($this->never()) + ->method('save'); + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->with($this->jsonString) + ->willReturn($this->data); + $this->fileIteratorFactoryMock->method('create') + ->willReturn($this->fileIteratorMock); + $this->factory->getValidatorConfig(); + $this->factory->getValidatorConfig(); + } + public function testCreateValidatorBuilder() { - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->_validatorConfig->expects( - $this->once() - )->method( - 'createValidatorBuilder' - )->with( - 'test', - 'class', - [] - )->will( - $this->returnValue( - $objectManager->getObject(\Magento\Framework\Validator\Builder::class, ['constraints' => []]) - ) - ); - $factory = new \Magento\Framework\Validator\Factory( - $this->_objectManager, - $this->_config, - $this->cache - ); + $this->readerMock->method('getConfigurationFiles') + ->with('validation.xml') + ->willReturn($this->fileIteratorMock); + $this->fileIteratorMock->method('toArray') + ->willReturn($this->data); + $builderMock = $this->getMock(\Magento\Framework\Validator\Builder::class, [], [], '', false); + $this->validatorConfigMock->expects($this->once()) + ->method('createValidatorBuilder') + ->with('test', 'class', []) + ->willReturn($builderMock); $this->assertInstanceOf( \Magento\Framework\Validator\Builder::class, - $factory->createValidatorBuilder('test', 'class', []) + $this->factory->createValidatorBuilder('test', 'class', []) ); } - /** - * Test createValidatorBuilder call - */ public function testCreateValidator() { - $this->_validatorConfig->expects( - $this->once() - )->method( - 'createValidator' - )->with( - 'test', - 'class', - [] - )->will( - $this->returnValue(new \Magento\Framework\Validator()) - ); - $factory = new \Magento\Framework\Validator\Factory( - $this->_objectManager, - $this->_config, - $this->cache + $this->readerMock->method('getConfigurationFiles') + ->with('validation.xml') + ->willReturn($this->fileIteratorMock); + $this->fileIteratorMock->method('toArray') + ->willReturn($this->data); + $validatorMock = $this->getMock(\Magento\Framework\Validator::class, [], [], '', false); + $this->validatorConfigMock->expects($this->once()) + ->method('createValidator') + ->with('test', 'class', []) + ->willReturn($validatorMock); + $this->assertInstanceOf( + \Magento\Framework\Validator::class, + $this->factory->createValidator('test', 'class', []) ); - $this->assertInstanceOf(\Magento\Framework\Validator::class, $factory->createValidator('test', 'class', [])); } } diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/LocaleTest.php b/lib/internal/Magento/Framework/Validator/Test/Unit/LocaleTest.php index 673a5616020da..d1da2ba354a61 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/LocaleTest.php +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/LocaleTest.php @@ -1,6 +1,6 @@ validator = new UrlValidator(); + } + + /** + * @param array $allowedSchemes + * @param string $url + * @param bool $expectedResult + * @dataProvider isValidDataProvider + */ + public function testIsValid(array $allowedSchemes, $url, $expectedResult) + { + $this->assertSame($expectedResult, $this->validator->isValid($url, $allowedSchemes)); + } + + /** + * @return array + */ + public function isValidDataProvider() + { + return [ + [ + 'allowedSchemes' => [], + 'url' => 'http://example.com', + 'expectedResult' => true, + ], + [ + 'allowedSchemes' => ['http'], + 'url' => 'http://example.com', + 'expectedResult' => true, + ], + [ + 'allowedSchemes' => [], + 'url' => 'https://example.com', + 'expectedResult' => true, + ], + [ + 'allowedSchemes' => ['https'], + 'url' => 'https://example.com', + 'expectedResult' => true, + ], + [ + 'allowedSchemes' => [], + 'url' => 'http://example.com_test', + 'expectedResult' => false, + ], + [ + 'allowedSchemes' => [], + 'url' => 'ftp://example.com', + 'expectedResult' => true, + ], + [ + 'allowedSchemes' => ['ftp'], + 'url' => 'ftp://example.com', + 'expectedResult' => true, + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/ValidatorAbstractTest.php b/lib/internal/Magento/Framework/Validator/Test/Unit/ValidatorAbstractTest.php index f7e03928fd03d..0f496c9bbae28 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/ValidatorAbstractTest.php +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/ValidatorAbstractTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_builder_instance.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_builder_instance.xml index 9a2c90714d526..9e4a25549084b 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_builder_instance.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_builder_instance.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_child_for_option.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_child_for_option.xml index 9aea586b4bee7..0cc14bf204049 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_child_for_option.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_child_for_option.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_constraint.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_constraint.xml index 57944f0143b2f..4b7b0a24e6772 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_constraint.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_constraint.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_content_for_callback.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_content_for_callback.xml index 3a61e4575ef85..9a07e7bc1bdf2 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_content_for_callback.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_content_for_callback.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_entity_callback.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_entity_callback.xml index ca4bd7fcd527c..8b3ff7a17ee3e 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_entity_callback.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_entity_callback.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method.xml index c8ed7062f0b5a..a13efa48945ca 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method_callback.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method_callback.xml index 2b7267be73a63..14ef83699b01d 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method_callback.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/invalid_method_callback.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/multiple_callback_in_argument.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/multiple_callback_in_argument.xml index 7d9e2a81dbd28..422d097360eef 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/multiple_callback_in_argument.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/multiple_callback_in_argument.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_class_for_constraint.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_class_for_constraint.xml index 86280ce54b062..042932dea0f17 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_class_for_constraint.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_class_for_constraint.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_constraint.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_constraint.xml index 61dcec47f583f..63b15da6656c5 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_constraint.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_constraint.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_entity.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_entity.xml index 94ee985d62511..0b848083efefc 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_entity.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_entity.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_group.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_group.xml index 17c388ee915ab..79121eb16ff65 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_group.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_group.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_rule.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_rule.xml index 483da577d5f9f..82bc468323460 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_rule.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_name_for_rule.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_rule_for_reference.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_rule_for_reference.xml index 812d6f862d839..500e52d20ed65 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_rule_for_reference.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/no_rule_for_reference.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/not_unique_use.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/not_unique_use.xml index 97468d6448e3e..07571c6164b84 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/not_unique_use.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/negative/not_unique_use.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/builder/validation.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/builder/validation.xml index fb4693b450797..9ba4ccdeb2eed 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/builder/validation.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/builder/validation.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_a/validation.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_a/validation.xml index 87348b1c340b6..97b0880fd9b8b 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_a/validation.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_a/validation.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_b/validation.xml b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_b/validation.xml index c060e26469cb1..ba3ef4c988137 100644 --- a/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_b/validation.xml +++ b/lib/internal/Magento/Framework/Validator/Test/Unit/_files/validation/positive/module_b/validation.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/Validator/Timezone.php b/lib/internal/Magento/Framework/Validator/Timezone.php index ec221fc308705..0e5f87c7724a9 100644 --- a/lib/internal/Magento/Framework/Validator/Timezone.php +++ b/lib/internal/Magento/Framework/Validator/Timezone.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/ValidatorFactory.php b/lib/internal/Magento/Framework/ValidatorFactory.php index 6508be8bf243f..efdaf300e7917 100644 --- a/lib/internal/Magento/Framework/ValidatorFactory.php +++ b/lib/internal/Magento/Framework/ValidatorFactory.php @@ -1,6 +1,6 @@ viewConfig->getViewConfig([ - 'area' => $assetContext->getAreaCode(), - 'themeModel' => $this->themeList->getThemeByFullPath( - $assetContext->getAreaCode() . '/' . $assetContext->getThemePath() - ) - ]); + $themePath = $assetContext->getAreaCode() . '/' . $assetContext->getThemePath(); + if (!isset($this->config[$themePath])) { + $this->config[$themePath] = $this->viewConfig->getViewConfig([ + 'area' => $assetContext->getAreaCode(), + 'themeModel' => $this->getThemeProvider()->getThemeByFullPath( + $themePath + ) + ]); + } + + return $this->config[$themePath]; } /** @@ -83,7 +100,19 @@ public function getPartSize(FallbackContext $assetContext) case 'MB': return (int)$size * 1024; default: - return (int)$size / 1024; + return (int)($size / 1024); } } + + /** + * @return ThemeProviderInterface + */ + private function getThemeProvider() + { + if (null === $this->themeProvider) { + $this->themeProvider = ObjectManager::getInstance()->get(ThemeProviderInterface::class); + } + + return $this->themeProvider; + } } diff --git a/lib/internal/Magento/Framework/View/Asset/Bundle/ConfigInterface.php b/lib/internal/Magento/Framework/View/Asset/Bundle/ConfigInterface.php index 2c9f113bf5f42..cfd838b9f26de 100644 --- a/lib/internal/Magento/Framework/View/Asset/Bundle/ConfigInterface.php +++ b/lib/internal/Magento/Framework/View/Asset/Bundle/ConfigInterface.php @@ -1,6 +1,6 @@ area = $areaType; $this->theme = $themePath; $this->locale = $localeCode; - $this->isSecure = $isSecure; parent::__construct($baseUrl, DirectoryList::STATIC_VIEW, $this->generatePath()); } @@ -103,6 +91,6 @@ private function generatePath() */ public function getConfigPath() { - return $this->getPath() . ($this->isSecure ? '/' . self::SECURE_PATH : ''); + return $this->getPath(); } } diff --git a/lib/internal/Magento/Framework/View/Asset/File/FallbackContextFactory.php b/lib/internal/Magento/Framework/View/Asset/File/FallbackContextFactory.php index cd4df0bc49fbf..36fcade1682bb 100644 --- a/lib/internal/Magento/Framework/View/Asset/File/FallbackContextFactory.php +++ b/lib/internal/Magento/Framework/View/Asset/File/FallbackContextFactory.php @@ -1,6 +1,6 @@ tmpDirectory->isExist($this->lockFilePath)) { - $lockTime = (int) $this->tmpDirectory->readFile($this->lockFilePath); - if ((time() - $lockTime) >= self::MAX_LOCK_TIME) { - $this->tmpDirectory->delete($this->lockFilePath); + try { + $lockTime = (int)$this->tmpDirectory->readFile($this->lockFilePath); + if ((time() - $lockTime) >= self::MAX_LOCK_TIME) { + $this->tmpDirectory->delete($this->lockFilePath); + + return false; + } + } catch (FileSystemException $e) { return false; } diff --git a/lib/internal/Magento/Framework/View/Asset/LockerProcessInterface.php b/lib/internal/Magento/Framework/View/Asset/LockerProcessInterface.php index b2a2c821b1965..df3b3bf38e39d 100644 --- a/lib/internal/Magento/Framework/View/Asset/LockerProcessInterface.php +++ b/lib/internal/Magento/Framework/View/Asset/LockerProcessInterface.php @@ -1,6 +1,6 @@ filesystem = $filesystem; } + /** + * @deprecated + * @return Source + */ + private function getAssetSource() + { + if (!$this->assetSource) { + $this->assetSource = ObjectManager::getInstance()->get(Source::class); + } + return $this->assetSource; + } + /** * {@inheritdoc} */ public function merge(array $assetsToMerge, \Magento\Framework\View\Asset\LocalInterface $resultAsset) { - $sourceDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT); + $rootDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT); $mTime = null; /** @var \Magento\Framework\View\Asset\MergeableInterface $asset */ foreach ($assetsToMerge as $asset) { - $mTime .= $sourceDir->stat($sourceDir->getRelativePath($asset->getSourceFile()))['mtime']; + $sourceFile = $this->getAssetSource()->findSource($asset); + $mTime .= $rootDir->stat($rootDir->getRelativePath($sourceFile))['mtime']; } + if (null === $mTime) { return; // nothing to merge } diff --git a/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Direct.php b/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Direct.php index 68cc706ad9bdf..de9248b8fe10a 100644 --- a/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Direct.php +++ b/lib/internal/Magento/Framework/View/Asset/MergeStrategy/Direct.php @@ -1,6 +1,6 @@ composeMergedContent($assetsToMerge, $resultAsset); - $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); - $dir->writeFile($resultAsset->getPath(), $mergedContent); + $filePath = $resultAsset->getPath(); + $staticDir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); + $tmpDir = $this->filesystem->getDirectoryWrite(DirectoryList::TMP); + $tmpDir->writeFile($filePath, $mergedContent); + $tmpDir->renameFile($filePath, $filePath, $staticDir); } /** diff --git a/lib/internal/Magento/Framework/View/Asset/MergeStrategy/FileExists.php b/lib/internal/Magento/Framework/View/Asset/MergeStrategy/FileExists.php index 211f3daed3c91..60339fa2d7542 100644 --- a/lib/internal/Magento/Framework/View/Asset/MergeStrategy/FileExists.php +++ b/lib/internal/Magento/Framework/View/Asset/MergeStrategy/FileExists.php @@ -1,6 +1,6 @@ appState->getMode() != State::MODE_DEVELOPER && - (bool)$this->scopeConfig->isSetFlag( - sprintf(self::XML_PATH_MINIFICATION_ENABLED, $contentType), - $this->scope - ); + if (!isset($this->configCache[self::XML_PATH_MINIFICATION_ENABLED][$contentType])) { + $this->configCache[self::XML_PATH_MINIFICATION_ENABLED][$contentType] = + $this->appState->getMode() != State::MODE_DEVELOPER && + (bool)$this->scopeConfig->isSetFlag( + sprintf(self::XML_PATH_MINIFICATION_ENABLED, $contentType), + $this->scope + ); + } + + return $this->configCache[self::XML_PATH_MINIFICATION_ENABLED][$contentType]; } /** @@ -131,15 +138,15 @@ public function isExcluded($filename) */ public function getExcludes($contentType) { - if (!isset($this->excludes[$contentType])) { - $this->excludes[$contentType] = []; + if (!isset($this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType])) { + $this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType] = []; $key = sprintf(self::XML_PATH_MINIFICATION_EXCLUDES, $contentType); foreach (explode("\n", $this->scopeConfig->getValue($key, $this->scope)) as $exclude) { if (trim($exclude) != '') { - $this->excludes[$contentType][] = trim($exclude); + $this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType][] = trim($exclude); } }; } - return $this->excludes[$contentType]; + return $this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType]; } } diff --git a/lib/internal/Magento/Framework/View/Asset/NotationResolver/Module.php b/lib/internal/Magento/Framework/View/Asset/NotationResolver/Module.php index a6a14c2513b64..d84ef3ed26590 100644 --- a/lib/internal/Magento/Framework/View/Asset/NotationResolver/Module.php +++ b/lib/internal/Magento/Framework/View/Asset/NotationResolver/Module.php @@ -1,6 +1,6 @@ assetRepo->getStaticViewFileContext(); switch ($placeholder) { case self::VAR_BASE_URL_PATH: - return $context->getBaseUrl() . $context->getPath(); + return '{{' . self::VAR_BASE_URL_PATH . '}}' . $context->getAreaCode() . + ($context->getThemePath() ? '/' . $context->getThemePath() . '/' : '') . + '{{locale}}'; default: return ''; } diff --git a/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php b/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php index 0f289c74538ae..16caa3bb89e80 100644 --- a/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php +++ b/lib/internal/Magento/Framework/View/Asset/PreProcessor/AlternativeSource.php @@ -1,6 +1,6 @@ themeList->getThemeByFullPath($area . '/' . $theme); + $params['themeModel'] = $this->getThemeProvider()->getThemeByFullPath($area . '/' . $theme); if (!$params['themeModel']) { throw new \UnexpectedValueException("Could not find theme '$theme' for area '$area'"); } @@ -158,6 +166,18 @@ public function updateDesignParams(array &$params) return $this; } + /** + * @return ThemeProviderInterface + */ + private function getThemeProvider() + { + if (null === $this->themeProvider) { + $this->themeProvider = ObjectManager::getInstance()->get(ThemeProviderInterface::class); + } + + return $this->themeProvider; + } + /** * Get default design parameter * @@ -248,8 +268,7 @@ private function getFallbackContext($urlType, $isSecure, $area, $themePath, $loc 'baseUrl' => $url, 'areaType' => $area, 'themePath' => $themePath, - 'localeCode' => $locale, - 'isSecure' => $isSecure + 'localeCode' => $locale ] ); } diff --git a/lib/internal/Magento/Framework/View/Asset/Source.php b/lib/internal/Magento/Framework/View/Asset/Source.php index 1bde94402d1a8..d59f48a136274 100644 --- a/lib/internal/Magento/Framework/View/Asset/Source.php +++ b/lib/internal/Magento/Framework/View/Asset/Source.php @@ -1,6 +1,6 @@ themeList->getThemeByFullPath($context->getAreaCode() . '/' . $context->getThemePath()); + $themeModel = $this->getThemeProvider()->getThemeByFullPath( + $context->getAreaCode() . '/' . $context->getThemePath() + ); $sourceFile = $this->fallback->getFile( $context->getAreaCode(), $themeModel, @@ -229,6 +239,18 @@ private function findFileThroughFallback( return $sourceFile; } + /** + * @return ThemeProviderInterface + */ + private function getThemeProvider() + { + if (null === $this->themeProvider) { + $this->themeProvider = ObjectManager::getInstance()->get(ThemeProviderInterface::class); + } + + return $this->themeProvider; + } + /** * Find asset file by simply appending its path to the directory in context * diff --git a/lib/internal/Magento/Framework/View/Asset/SourceFileGeneratorInterface.php b/lib/internal/Magento/Framework/View/Asset/SourceFileGeneratorInterface.php index 860a3ed0d0bb5..38108cfddd7ca 100644 --- a/lib/internal/Magento/Framework/View/Asset/SourceFileGeneratorInterface.php +++ b/lib/internal/Magento/Framework/View/Asset/SourceFileGeneratorInterface.php @@ -1,6 +1,6 @@ getCode(); + $key = $currentTheme->getFullPath(); if (isset($this->viewConfigs[$key])) { return $this->viewConfigs[$key]; } diff --git a/lib/internal/Magento/Framework/View/ConfigInterface.php b/lib/internal/Magento/Framework/View/ConfigInterface.php index 21cb20bc80815..93ec4ff6869b1 100644 --- a/lib/internal/Magento/Framework/View/ConfigInterface.php +++ b/lib/internal/Magento/Framework/View/ConfigInterface.php @@ -1,6 +1,6 @@ _loadByPath($themeKey, $area); } - if (!$themeModel->getId()) { + if (!$themeModel->getCode()) { throw new \LogicException("Unable to load theme by specified key: '{$themeKey}'"); } $this->_addTheme($themeModel); diff --git a/lib/internal/Magento/Framework/View/Design/Theme/Image.php b/lib/internal/Magento/Framework/View/Design/Theme/Image.php index c6725f07418f9..9093759526cf9 100644 --- a/lib/internal/Magento/Framework/View/Design/Theme/Image.php +++ b/lib/internal/Magento/Framework/View/Design/Theme/Image.php @@ -1,6 +1,6 @@ scopeConfig = $scopeConfig; $this->exceptionConfigPath = $exceptionConfigPath; $this->scopeType = $scopeType; + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); } /** @@ -65,7 +78,7 @@ public function getThemeByRequest(\Magento\Framework\App\Request\Http $request) if (!$expressions) { return false; } - $expressions = unserialize($expressions); + $expressions = $this->serializer->unserialize($expressions); foreach ($expressions as $rule) { if (preg_match($rule['regexp'], $userAgent)) { return $rule['value']; diff --git a/lib/internal/Magento/Framework/View/DesignInterface.php b/lib/internal/Magento/Framework/View/DesignInterface.php index e2c0e387dbbb5..6429166932d8e 100644 --- a/lib/internal/Magento/Framework/View/DesignInterface.php +++ b/lib/internal/Magento/Framework/View/DesignInterface.php @@ -1,6 +1,6 @@ _eventManager->dispatch('view_block_abstract_to_html_before', ['block' => $this]); - if ($this->_scopeConfig->getValue( - 'advanced/modules_disable_output/' . $this->getModuleName(), - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - )) { - return ''; - } + $this->getModuleName(); $html = $this->_loadCache(); if ($html === false) { @@ -670,6 +665,18 @@ public function toHtml() } $html = $this->_afterToHtml($html); + /** @var \Magento\Framework\DataObject */ + $transportObject = new \Magento\Framework\DataObject( + [ + 'html' => $html, + ] + ); + $this->_eventManager->dispatch('view_block_abstract_to_html_after', [ + 'block' => $this, + 'transport' => $transportObject + ]); + $html = $transportObject->getHtml(); + return $html; } diff --git a/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php b/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php new file mode 100644 index 0000000000000..9fa51aa6e4035 --- /dev/null +++ b/lib/internal/Magento/Framework/View/Element/Block/ArgumentInterface.php @@ -0,0 +1,14 @@ +getClass() . '" title="' . - $this->getTitle() . + $this->escapeHtml($this->getTitle()) . '" ' . $this->getExtraParams() . '>'; @@ -166,7 +166,8 @@ protected function _toHtml() } if (is_array($value)) { - $html .= ''; + $html .= ''; foreach ($value as $keyGroup => $optionGroup) { if (!is_array($optionGroup)) { $optionGroup = ['value' => $keyGroup, 'label' => $optionGroup]; @@ -204,10 +205,10 @@ protected function _optionToHtml($option, $selected = false) foreach ($option['params'] as $key => $value) { if (is_array($value)) { foreach ($value as $keyMulti => $valueMulti) { - $params .= sprintf(' %s="%s" ', $keyMulti, $valueMulti); + $params .= sprintf(' %s="%s" ', $keyMulti, $this->escapeHtml($valueMulti)); } } else { - $params .= sprintf(' %s="%s" ', $key, $value); + $params .= sprintf(' %s="%s" ', $key, $this->escapeHtml($value)); } } } diff --git a/lib/internal/Magento/Framework/View/Element/Js/Components.php b/lib/internal/Magento/Framework/View/Element/Js/Components.php index 27e131d5ab127..1c53382b2509f 100644 --- a/lib/internal/Magento/Framework/View/Element/Js/Components.php +++ b/lib/internal/Magento/Framework/View/Element/Js/Components.php @@ -1,6 +1,6 @@ cache->load(static::CACHE_ID); if ($cachedData === false) { $data = $uiReader->read(); - $this->cache->save(serialize($data), static::CACHE_ID); + $this->cache->save($this->getSerializer()->serialize($data), static::CACHE_ID); } else { - $data = unserialize($cachedData); + $data = $this->getSerializer()->unserialize($cachedData); } $this->prepareComponentData($data); } @@ -109,4 +114,19 @@ protected function prepareComponentData(array $componentsData) $this->setComponentData($name, reset($data)); } } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Template.php b/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Template.php index 79d185b2b26a7..c476c650d9b16 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Template.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Provider/Template.php @@ -1,13 +1,10 @@ aggregatedFileCollector = $aggregatedFileCollector; @@ -81,7 +83,9 @@ public function __construct( $this->aggregatedFileCollectorFactory = $aggregatedFileCollectorFactory; $cachedTemplates = $this->cache->load(static::CACHE_ID); - $this->cachedTemplates = $cachedTemplates === false ? [] : unserialize($cachedTemplates); + $this->cachedTemplates = $cachedTemplates === false ? [] : $this->getSerializer()->unserialize( + $cachedTemplates + ); } /** @@ -104,8 +108,23 @@ public function getTemplate($template) 'domMerger' => $this->domMerger ] )->getContent(); - $this->cache->save(serialize($this->cachedTemplates), static::CACHE_ID); + $this->cache->save($this->getSerializer()->serialize($this->cachedTemplates), static::CACHE_ID); return $this->cachedTemplates[$hash]; } + + /** + * Get serializer + * + * @return \Magento\Framework\Serialize\SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if ($this->serializer === null) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\SerializerInterface::class); + } + return $this->serializer; + } } diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Reader.php b/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Reader.php index e2e8efdee89e2..c8bd5afe5074a 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Reader.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponent/Config/Reader.php @@ -1,6 +1,6 @@ handles[] = $handle; + } + + /** + * Get list of handles containing entity ID + * + * @return string[] + */ + public function getHandles() + { + return $this->handles; + } +} diff --git a/lib/internal/Magento/Framework/View/File.php b/lib/internal/Magento/Framework/View/File.php index 1751ddc67de51..96c842b03f731 100644 --- a/lib/internal/Magento/Framework/View/File.php +++ b/lib/internal/Magento/Framework/View/File.php @@ -1,6 +1,6 @@ * - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Framework\View\Helper; diff --git a/lib/internal/Magento/Framework/View/Helper/PathPattern.php b/lib/internal/Magento/Framework/View/Helper/PathPattern.php index 7ff51613dbd1a..6d677d77a3200 100644 --- a/lib/internal/Magento/Framework/View/Helper/PathPattern.php +++ b/lib/internal/Magento/Framework/View/Helper/PathPattern.php @@ -1,6 +1,6 @@ _elementClass = \Magento\Framework\View\Layout\Element::class; $this->_renderingOutput = new \Magento\Framework\DataObject(); + $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class); $this->_processorFactory = $processorFactory; $this->_eventManager = $eventManager; @@ -308,12 +318,19 @@ public function generateElements() $cacheId = 'structure_' . $this->getUpdate()->getCacheId(); $result = $this->cache->load($cacheId); if ($result) { - $this->readerContext = unserialize($result); + $data = $this->serializer->unserialize($result); + $this->getReaderContext()->getPageConfigStructure()->populateWithArray($data['pageConfigStructure']); + $this->getReaderContext()->getScheduledStructure()->populateWithArray($data['scheduledStructure']); } else { \Magento\Framework\Profiler::start('build_structure'); $this->readerPool->interpret($this->getReaderContext(), $this->getNode()); \Magento\Framework\Profiler::stop('build_structure'); - $this->cache->save(serialize($this->getReaderContext()), $cacheId, $this->getUpdate()->getHandles()); + + $data = [ + 'pageConfigStructure' => $this->getReaderContext()->getPageConfigStructure()->__toArray(), + 'scheduledStructure' => $this->getReaderContext()->getScheduledStructure()->__toArray(), + ]; + $this->cache->save($this->serializer->serialize($data), $cacheId, $this->getUpdate()->getHandles()); } $generatorContext = $this->generatorContextFactory->create( diff --git a/lib/internal/Magento/Framework/View/Layout/Argument/Interpreter/DataObject.php b/lib/internal/Magento/Framework/View/Layout/Argument/Interpreter/DataObject.php index ae284734696ad..8b60d1acebe5f 100644 --- a/lib/internal/Magento/Framework/View/Layout/Argument/Interpreter/DataObject.php +++ b/lib/internal/Magento/Framework/View/Layout/Argument/Interpreter/DataObject.php @@ -1,6 +1,6 @@ getAttribute('remove'), FILTER_VALIDATE_BOOLEAN); if ($elementRemove) { $scheduledStructure->setElementToRemoveList($elementName); - } else { - $data = $scheduledStructure->getStructureElementData($elementName, []); - $data['attributes'] = $this->mergeBlockAttributes($data, $currentElement); - $this->updateScheduledData($currentElement, $data); - $this->evaluateArguments($currentElement, $data); - $scheduledStructure->setStructureElementData($elementName, $data); + return; + } elseif ($currentElement->getAttribute('remove')) { + $scheduledStructure->unsetElementFromListToRemove($elementName); } + $data = $scheduledStructure->getStructureElementData($elementName, []); + $data['attributes'] = $this->mergeBlockAttributes($data, $currentElement); + $this->updateScheduledData($currentElement, $data); + $this->evaluateArguments($currentElement, $data); + $scheduledStructure->setStructureElementData($elementName, $data); } /** diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php index c4111a13c33b3..21058e26c5473 100755 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Container.php +++ b/lib/internal/Magento/Framework/View/Layout/Reader/Container.php @@ -1,6 +1,6 @@ getAttribute('name'); $containerRemove = filter_var($currentElement->getAttribute('remove'), FILTER_VALIDATE_BOOLEAN); - if ($containerRemove) { $scheduledStructure->setElementToRemoveList($containerName); - } else { - $this->mergeContainerAttributes($scheduledStructure, $currentElement); + return; + } elseif ($currentElement->getAttribute('remove')) { + $scheduledStructure->unsetElementFromListToRemove($containerName); } + $this->mergeContainerAttributes($scheduledStructure, $currentElement); } } diff --git a/lib/internal/Magento/Framework/View/Layout/Reader/Context.php b/lib/internal/Magento/Framework/View/Layout/Reader/Context.php index 15ef97b031b1d..423ce6455651f 100644 --- a/lib/internal/Magento/Framework/View/Layout/Reader/Context.php +++ b/lib/internal/Magento/Framework/View/Layout/Reader/Context.php @@ -1,6 +1,6 @@ scheduledStructure = isset($data['scheduledStructure']) ? $data['scheduledStructure'] : []; - $this->scheduledData = isset($data['scheduledData']) ? $data['scheduledData'] : []; - $this->scheduledElements = isset($data['scheduledElements']) ? $data['scheduledElements'] : []; - $this->scheduledMoves = isset($data['scheduledMoves']) ? $data['scheduledMoves'] : []; - $this->scheduledRemoves = isset($data['scheduledRemoves']) ? $data['scheduledRemoves'] : []; - $this->scheduledIfconfig = isset($data['scheduledIfconfig']) ? $data['scheduledIfconfig'] : []; - $this->scheduledPaths = isset($data['scheduledPaths']) ? $data['scheduledPaths'] : []; + $this->populateWithArray($data); } /** @@ -531,4 +540,44 @@ public function flushScheduledStructure() $this->scheduledElements = []; $this->scheduledStructure = []; } + + /** + * Reformat 'Layout scheduled structure' to array. + * + * @return array + */ + public function __toArray() + { + $result = []; + foreach ($this->serializableProperties as $property) { + $result[$property] = $this->{$property}; + } + + return $result; + } + + /** + * Update 'Layout scheduled structure' data. + * + * @param array $data + * @return void + */ + public function populateWithArray(array $data) + { + foreach ($this->serializableProperties as $property) { + $this->{$property} = $this->getArrayValueByKey($property, $data); + } + } + + /** + * Get value from array by key. + * + * @param string $key + * @param array $array + * @return array + */ + private function getArrayValueByKey($key, array $array) + { + return isset($array[$key]) ? $array[$key] : []; + } } diff --git a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php index 870f147a43634..b5b5711cb5f2c 100644 --- a/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php +++ b/lib/internal/Magento/Framework/View/Layout/ScheduledStructure/Helper.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd b/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd index 4966d7f88ffbc..21f27bf343a9d 100755 --- a/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/elements.xsd @@ -1,7 +1,7 @@ @@ -140,7 +140,7 @@ - + @@ -248,6 +248,7 @@ + diff --git a/lib/internal/Magento/Framework/View/Layout/etc/head.xsd b/lib/internal/Magento/Framework/View/Layout/etc/head.xsd index 7e26ed41a6941..141e42db113cb 100644 --- a/lib/internal/Magento/Framework/View/Layout/etc/head.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/head.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Layout/etc/html.xsd b/lib/internal/Magento/Framework/View/Layout/etc/html.xsd index 24a04fe922761..ddc12f3c413d0 100644 --- a/lib/internal/Magento/Framework/View/Layout/etc/html.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/html.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd b/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd index 6624495d3a8ff..b174d3008e93b 100755 --- a/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Layout/etc/layout_merged.xsd b/lib/internal/Magento/Framework/View/Layout/etc/layout_merged.xsd index d6faf66fdc094..665b7504255e0 100644 --- a/lib/internal/Magento/Framework/View/Layout/etc/layout_merged.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/layout_merged.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd b/lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd index b77c440ef2e6b..b4b9dcbb43948 100644 --- a/lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Layout/etc/page_layout.xsd b/lib/internal/Magento/Framework/View/Layout/etc/page_layout.xsd index 7d62f2b903d66..9ea11a18ad23c 100755 --- a/lib/internal/Magento/Framework/View/Layout/etc/page_layout.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/page_layout.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Layout/etc/page_types.xsd b/lib/internal/Magento/Framework/View/Layout/etc/page_types.xsd index 9cc119a646827..06088726fd598 100644 --- a/lib/internal/Magento/Framework/View/Layout/etc/page_types.xsd +++ b/lib/internal/Magento/Framework/View/Layout/etc/page_types.xsd @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/LayoutFactory.php b/lib/internal/Magento/Framework/View/LayoutFactory.php index 2890ec5cb8a15..86ac802f654d2 100644 --- a/lib/internal/Magento/Framework/View/LayoutFactory.php +++ b/lib/internal/Magento/Framework/View/LayoutFactory.php @@ -1,6 +1,6 @@ getFileLayoutUpdatesXml(); foreach ($layout->xpath("*[self::handle or self::layout][@id='{$handle}']") as $updateXml) { $this->_fetchRecursiveUpdates($updateXml); - $this->addUpdate($updateXml->innerXml()); + $updateInnerXml = $updateXml->innerXml(); + $this->validateUpdate($handle, $updateInnerXml); + $this->addUpdate($updateInnerXml); } \Magento\Framework\Profiler::stop($_profilerKey); @@ -563,12 +565,31 @@ protected function _fetchDbLayoutUpdates($handle) $updateStr = $this->_substitutePlaceholders($updateStr); $updateXml = $this->_loadXmlString($updateStr); $this->_fetchRecursiveUpdates($updateXml); - $this->addUpdate($updateXml->innerXml()); + $updateInnerXml = $updateXml->innerXml(); + $this->validateUpdate($handle, $updateInnerXml); + $this->addUpdate($updateInnerXml); \Magento\Framework\Profiler::stop($_profilerKey); return (bool)$updateStr; } + /** + * Validate layout update content, throw exception on failure. + * + * This method is used as a hook for plugins. + * + * @param string $handle + * @param string $updateXml + * @return void + * @throws \Exception + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @codeCoverageIgnore + */ + public function validateUpdate($handle, $updateXml) + { + return; + } + /** * Substitute placeholders {{placeholder_name}} with their values in XML string * diff --git a/lib/internal/Magento/Framework/View/Model/Layout/Translator.php b/lib/internal/Magento/Framework/View/Model/Layout/Translator.php index 0cbc336a44fd2..07539d8a3d693 100644 --- a/lib/internal/Magento/Framework/View/Model/Layout/Translator.php +++ b/lib/internal/Magento/Framework/View/Model/Layout/Translator.php @@ -1,6 +1,6 @@ assets; } + + /** + * Reformat 'Page config structure' to array. + * + * @return array + */ + public function __toArray() + { + $result = []; + foreach ($this->serializableProperties as $property) { + $result[$property] = $this->{$property}; + } + + return $result; + } + + /** + * Update 'Page config structure' data. + * + * @param array $data + * @return void + */ + public function populateWithArray(array $data) + { + foreach ($this->serializableProperties as $property) { + $this->{$property} = $this->getArrayValueByKey($property, $data); + } + } + + /** + * Get value from array by key. + * + * @param string $key + * @param array $array + * @return array + */ + private function getArrayValueByKey($key, array $array) + { + return isset($array[$key]) ? $array[$key] : []; + } } diff --git a/lib/internal/Magento/Framework/View/Page/ConfigFactory.php b/lib/internal/Magento/Framework/View/Page/ConfigFactory.php index d0fed31c244d9..c4071567de02f 100644 --- a/lib/internal/Magento/Framework/View/Page/ConfigFactory.php +++ b/lib/internal/Magento/Framework/View/Page/ConfigFactory.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/View/Render/RenderFactory.php b/lib/internal/Magento/Framework/View/Render/RenderFactory.php index 1b96a01e84451..4fc8a7e065e4a 100644 --- a/lib/internal/Magento/Framework/View/Render/RenderFactory.php +++ b/lib/internal/Magento/Framework/View/Render/RenderFactory.php @@ -1,6 +1,6 @@ request = $context->getRequest(); $this->assetRepo = $context->getAssetRepository(); @@ -127,6 +134,8 @@ public function __construct( $this->viewFileSystem = $context->getViewFileSystem(); $this->pageConfigRendererFactory = $pageConfigRendererFactory; $this->template = $template; + $this->entitySpecificHandlesList = $entitySpecificHandlesList + ?: \Magento\Framework\App\ObjectManager::getInstance()->get(View\EntitySpecificHandlesList::class); parent::__construct( $context, $layoutFactory, @@ -205,17 +214,23 @@ public function getConfig() * * @param array|null $parameters page parameters * @param string|null $defaultHandle + * @param bool $entitySpecific * @return bool */ - public function addPageLayoutHandles(array $parameters = [], $defaultHandle = null) + public function addPageLayoutHandles(array $parameters = [], $defaultHandle = null, $entitySpecific = true) { $handle = $defaultHandle ? $defaultHandle : $this->getDefaultLayoutHandle(); $pageHandles = [$handle]; foreach ($parameters as $key => $value) { - $pageHandles[] = $handle . '_' . $key . '_' . $value; + $pageHandle = $handle . '_' . $key . '_' . $value; + $pageHandles[] = $pageHandle; + if ($entitySpecific) { + $this->entitySpecificHandlesList->addHandle($pageHandle); + } } // Do not sort array going into add page handles. Ensure default layout handle is added first. - return $this->addHandle($pageHandles); + $this->addHandle($pageHandles); + return true; } /** diff --git a/lib/internal/Magento/Framework/View/Result/PageFactory.php b/lib/internal/Magento/Framework/View/Result/PageFactory.php index aa35b9d3e24f1..6aba62bf6a41c 100644 --- a/lib/internal/Magento/Framework/View/Result/PageFactory.php +++ b/lib/internal/Magento/Framework/View/Result/PageFactory.php @@ -1,6 +1,6 @@ fallbackContext = $this->objectManager->getObject( @@ -49,8 +47,7 @@ public function testGetConfigPath( 'baseUrl' => $baseUrl, 'areaType' => $areaType, 'themePath' => $themePath, - 'localeCode' => $localeCode, - 'isSecure' => $isSecure + 'localeCode' => $localeCode ] ); $this->assertEquals($expectedResult, $this->fallbackContext->getConfigPath()); @@ -64,7 +61,6 @@ public function getConfigPathDataProvider() 'areaType' => 'frontend', 'themePath' => 'Magento/blank', 'localeCode' => 'en_US', - 'isSecure' => false, 'expectedResult' => 'frontend/Magento/blank/en_US' ], 'https' => [ @@ -72,8 +68,7 @@ public function getConfigPathDataProvider() 'areaType' => 'frontend', 'themePath' => 'Magento/blank', 'localeCode' => 'en_US', - 'isSecure' => true, - 'expectedResult' => 'frontend/Magento/blank/en_US/secure' + 'expectedResult' => 'frontend/Magento/blank/en_US' ] ]; } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php index 1ad1ab80fdef4..45c630dcf90c4 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/FileTest.php @@ -1,6 +1,6 @@ with(DirectoryList::STATIC_VIEW) ->will($this->returnValue($this->targetDir)); $this->checksum = new Checksum($this->mergerMock, $filesystem); + $this->assetSource = $this->getMockBuilder(Source::class) + ->disableOriginalConstructor() + ->getMock(); + + $reflection = new \ReflectionClass(Checksum::class); + $reflectionProperty = $reflection->getProperty('assetSource'); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->checksum, $this->assetSource); + $this->resultAsset = $this->getMock(\Magento\Framework\View\Asset\File::class, [], [], '', false); } @@ -114,9 +129,17 @@ public function testMergeMtimeUnchanged() private function getAssetsToMerge() { $one = $this->getMock(\Magento\Framework\View\Asset\File::class, [], [], '', false); - $one->expects($this->once())->method('getSourceFile')->will($this->returnValue('/dir/file/one.txt')); $two = $this->getMock(\Magento\Framework\View\Asset\File::class, [], [], '', false); - $two->expects($this->once())->method('getSourceFile')->will($this->returnValue('/dir/file/two.txt')); + $one->expects($this->never()) + ->method('getSourceFile'); + $two->expects($this->never()) + ->method('getSourceFile'); + + $this->assetSource->expects($this->exactly(2)) + ->method('findSource') + ->withConsecutive([$one], [$two]) + ->willReturnOnConsecutiveCalls('/dir/file/one.txt', '/dir/file/two.txt'); + $this->sourceDir->expects($this->exactly(2)) ->method('getRelativePath') ->will($this->onConsecutiveCalls('file/one.txt', 'file/two.txt')); diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/DirectTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/DirectTest.php index 23041feb2b8c6..33ad9608109e9 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/DirectTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/DirectTest.php @@ -1,10 +1,11 @@ cssUrlResolver = $this->getMock(\Magento\Framework\View\Url\CssResolver::class); $filesystem = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); - $this->writeDir = $this->getMockForAbstractClass(\Magento\Framework\Filesystem\Directory\WriteInterface::class); + $this->staticDir = $this->getMockBuilder(WriteInterface::class)->getMockForAbstractClass(); + $this->tmpDir = $this->getMockBuilder(WriteInterface::class)->getMockForAbstractClass(); $filesystem->expects($this->any()) ->method('getDirectoryWrite') - ->with(DirectoryList::STATIC_VIEW) - ->will($this->returnValue($this->writeDir)); + ->willReturnMap([ + [DirectoryList::STATIC_VIEW, \Magento\Framework\Filesystem\DriverPool::FILE, $this->staticDir], + [DirectoryList::TMP, \Magento\Framework\Filesystem\DriverPool::FILE, $this->tmpDir], + ]); $this->resultAsset = $this->getMock(\Magento\Framework\View\Asset\File::class, [], [], '', false); $this->object = new Direct($filesystem, $this->cssUrlResolver); } @@ -47,7 +56,9 @@ protected function setUp() public function testMergeNoAssets() { $this->resultAsset->expects($this->once())->method('getPath')->will($this->returnValue('foo/result')); - $this->writeDir->expects($this->once())->method('writeFile')->with('foo/result', ''); + $this->staticDir->expects($this->never())->method('writeFile'); + $this->tmpDir->expects($this->once())->method('writeFile')->with('foo/result', ''); + $this->tmpDir->expects($this->once())->method('renameFile')->with('foo/result', 'foo/result', $this->staticDir); $this->object->merge([], $this->resultAsset); } @@ -55,7 +66,9 @@ public function testMergeGeneric() { $this->resultAsset->expects($this->once())->method('getPath')->will($this->returnValue('foo/result')); $assets = $this->prepareAssetsToMerge([' one', 'two']); // note leading space intentionally - $this->writeDir->expects($this->once())->method('writeFile')->with('foo/result', 'onetwo'); + $this->staticDir->expects($this->never())->method('writeFile'); + $this->tmpDir->expects($this->once())->method('writeFile')->with('foo/result', 'onetwo'); + $this->tmpDir->expects($this->once())->method('renameFile')->with('foo/result', 'foo/result', $this->staticDir); $this->object->merge($assets, $this->resultAsset); } @@ -73,7 +86,9 @@ public function testMergeCss() ->method('aggregateImportDirectives') ->with('12') ->will($this->returnValue('1020')); - $this->writeDir->expects($this->once())->method('writeFile')->with('foo/result', '1020'); + $this->staticDir->expects($this->never())->method('writeFile'); + $this->tmpDir->expects($this->once())->method('writeFile')->with('foo/result', '1020'); + $this->tmpDir->expects($this->once())->method('renameFile')->with('foo/result', 'foo/result', $this->staticDir); $this->object->merge($assets, $this->resultAsset); } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/FileExistsTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/FileExistsTest.php index 2354411700ce8..d42ad9c988429 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/FileExistsTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MergeStrategy/FileExistsTest.php @@ -1,6 +1,6 @@ context = $this->getMock( - \Magento\Framework\View\Asset\File\Context::class, - null, - [$baseUrl, DirectoryList::STATIC_VIEW, $path] - ); + $this->context = $this->getMockBuilder(FallbackContext::class) + ->disableOriginalConstructor() + ->getMock(); + $this->context->expects($this->once()) + ->method('getAreaCode') + ->willReturn($area); + $this->context->expects($this->exactly(2)) + ->method('getThemePath') + ->willReturn($themePath); - $this->assetRepo = $this->getMock(\Magento\Framework\View\Asset\Repository::class, [], [], '', false); + $this->assetRepo = $this->getMockBuilder(Repository::class) + ->disableOriginalConstructor() + ->getMock(); $this->assetRepo->expects($this->any()) ->method('getStaticViewFileContext') ->will($this->returnValue($this->context)); - $this->object = new \Magento\Framework\View\Asset\NotationResolver\Variable($this->assetRepo); + $this->object = new Variable($this->assetRepo); } /** @@ -61,7 +69,7 @@ public function testConvertVariableNotation($path, $expectedResult) public function convertVariableNotationDataProvider() { return [ - ['{{base_url_path}}/file.ext', 'http://example.com/pub/static/frontend/Magento/blank/en_US/file.ext'], + ['{{base_url_path}}/file.ext', '{{base_url_path}}frontend/Magento/blank/{{locale}}/file.ext'], ]; } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/AlternativeSourceTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/AlternativeSourceTest.php index a4a2930143f81..becd5643df25c 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/AlternativeSourceTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/PreProcessor/AlternativeSourceTest.php @@ -1,6 +1,6 @@ designMock = $this->getMockBuilder(\Magento\Framework\View\DesignInterface::class) ->disableOriginalConstructor() ->getMock(); - $this->listMock = $this->getMockBuilder(\Magento\Framework\View\Design\Theme\ListInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $this->themeProvider = $this->getMock(ThemeProviderInterface::class); $this->sourceMock = $this->getMockBuilder(\Magento\Framework\View\Asset\Source::class) ->disableOriginalConstructor() ->getMock(); @@ -103,17 +103,17 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->repository = new Repository( - $this->urlMock, - $this->designMock, - $this->listMock, - $this->sourceMock, - $this->httpMock, - $this->fileFactoryMock, - $this->fallbackFactoryMock, - $this->contextFactoryMock, - $this->remoteFactoryMock - ); + $this->repository = (new ObjectManager($this))->getObject(Repository::class, [ + 'baseUrl' => $this->urlMock, + 'design' => $this->designMock, + 'themeProvider' => $this->themeProvider, + 'assetSource' => $this->sourceMock, + 'request' => $this->httpMock, + 'fileFactory' => $this->fileFactoryMock, + 'fallbackContextFactory' => $this->fallbackFactoryMock, + 'contextFactory' => $this->contextFactoryMock, + 'remoteFactory' => $this->remoteFactoryMock + ]); } /** @@ -124,7 +124,7 @@ protected function setUp() public function testUpdateDesignParamsWrongTheme() { $params = ['area' => 'area', 'theme' => 'nonexistent_theme']; - $this->listMock->expects($this->once()) + $this->themeProvider->expects($this->once()) ->method('getThemeByFullPath') ->with('area/nonexistent_theme') ->will($this->returnValue(null)); @@ -139,7 +139,7 @@ public function testUpdateDesignParamsWrongTheme() */ public function testUpdateDesignParams($params, $result) { - $this->listMock + $this->themeProvider ->expects($this->any()) ->method('getThemeByFullPath') ->willReturn('ThemeID'); @@ -169,7 +169,7 @@ public function updateDesignParamsDataProvider() */ public function testCreateAsset() { - $this->listMock + $this->themeProvider ->expects($this->any()) ->method('getThemeByFullPath') ->willReturnArgument(0); @@ -185,8 +185,7 @@ public function testCreateAsset() 'baseUrl' => '', 'areaType' => '', 'themePath' => 'Default', - 'localeCode' => '', - 'isSecure' => '', + 'localeCode' => '' ] ) ->willReturn($fallbackContextMock); @@ -231,7 +230,7 @@ public function testGetStaticViewFileContext() 'locale' => 'locale' ] ); - $this->listMock + $this->themeProvider ->expects($this->any()) ->method('getThemeByFullPath') ->willReturnArgument(0); @@ -251,8 +250,7 @@ public function testGetStaticViewFileContext() 'baseUrl' => '', 'areaType' => 'area', 'themePath' => '', - 'localeCode' => 'locale', - 'isSecure' => '', + 'localeCode' => 'locale' ] ) ->willReturn($fallbackContextMock); diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php index 66e33e4fe3140..fdc14e333e839 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/SourceTest.php @@ -1,6 +1,6 @@ preProcessorPool = $this->getMock( + $this->preProcessorPool = $this->getMock( \Magento\Framework\View\Asset\PreProcessor\Pool::class, [], [], '', false ); - $this->viewFileResolution = $this->getMock( + $this->viewFileResolution = $this->getMock( \Magento\Framework\View\Design\FileResolution\Fallback\StaticFile::class, [], [], '', false ); $this->theme = $this->getMockForAbstractClass(\Magento\Framework\View\Design\ThemeInterface::class); /** @var \Magento\Framework\App\Config\ScopeConfigInterface $config */ - $this->chainFactory = $this->getMockBuilder( + $this->chainFactory = $this->getMockBuilder( \Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface::class) ->getMock(); $this->chain = $this->getMockBuilder(\Magento\Framework\View\Asset\PreProcessor\Chain::class) @@ -96,30 +98,30 @@ protected function setUp() ->method('create') ->willReturn($this->chain); - $themeList = $this->getMockForAbstractClass(\Magento\Framework\View\Design\Theme\ListInterface::class); - $themeList->expects($this->any()) + $themeProvider = $this->getMock(ThemeProviderInterface::class); + $themeProvider->expects($this->any()) ->method('getThemeByFullPath') ->with('frontend/magento_theme') ->willReturn($this->theme); - $this->readFactory = $this->getMock( - \Magento\Framework\Filesystem\Directory\ReadFactory::class, - [], - [], - '', - false + $this->readFactory = $this->getMock( + \Magento\Framework\Filesystem\Directory\ReadFactory::class, + [], + [], + '', + false ); $this->initFilesystem(); - $this->object = new Source( - $this->filesystem, - $this->readFactory, - $this->preProcessorPool, - $this->viewFileResolution, - $themeList, - $this->chainFactory - ); + $this->object = (new ObjectManager($this))->getObject(Source::class, [ + 'filesystem' => $this->filesystem, + 'readFactory' => $this->readFactory, + 'preProcessorPool' => $this->preProcessorPool, + 'fallback' => $this->viewFileResolution, + 'themeProvider' => $themeProvider, + 'chainFactory' => $this->chainFactory + ]); } /** @@ -229,11 +231,11 @@ public function getFileDataProvider() protected function initFilesystem() { $this->filesystem = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); - $this->rootDirRead = $this->getMockForAbstractClass( - \Magento\Framework\Filesystem\Directory\ReadInterface::class + $this->rootDirRead = $this->getMockForAbstractClass( + \Magento\Framework\Filesystem\Directory\ReadInterface::class ); - $this->staticDirRead = $this->getMockForAbstractClass( - \Magento\Framework\Filesystem\Directory\ReadInterface::class + $this->staticDirRead = $this->getMockForAbstractClass( + \Magento\Framework\Filesystem\Directory\ReadInterface::class ); $this->varDir = $this->getMockForAbstractClass(\Magento\Framework\Filesystem\Directory\WriteInterface::class); diff --git a/lib/internal/Magento/Framework/View/Test/Unit/BlockPoolTest.php b/lib/internal/Magento/Framework/View/Test/Unit/BlockPoolTest.php index b93e9b7a0e045..699dda0cd2f27 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/BlockPoolTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/BlockPoolTest.php @@ -1,6 +1,6 @@ getMock( \Magento\Theme\Model\Theme::class, - ['getCode'], + ['getFullPath'], [], '', false ); $themeMock->expects($this->atLeastOnce()) - ->method('getCode') + ->method('getFullPath') ->will($this->returnValue($themeCode)); $params = [ 'themeModel' => $themeMock, diff --git a/lib/internal/Magento/Framework/View/Test/Unit/ContextTest.php b/lib/internal/Magento/Framework/View/Test/Unit/ContextTest.php index 59e5b0e7a43f8..7225fee0c0ef4 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/ContextTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/ContextTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Theme\Model\Theme::class, [], [], '', false); - $theme->expects($this->exactly(3))->method('getId')->will($this->returnValue($expectedId)); + $theme->expects($this->exactly(2))->method('getId')->will($this->returnValue($expectedId)); $theme->expects($this->once())->method('getFullPath')->will($this->returnValue(null)); - + $theme->expects($this->once())->method('getCode')->willReturn($expectedId); $this->themeProviderMock->expects( $this->once() )->method( @@ -70,10 +70,10 @@ public function testCreateByPath() $path = 'frontend/Magento/luma'; $themeId = 7; $theme = $this->getMock(\Magento\Theme\Model\Theme::class, [], [], '', false); - $theme->expects($this->exactly(3))->method('getId')->will($this->returnValue($themeId)); + $theme->expects($this->exactly(2))->method('getId')->will($this->returnValue($themeId)); $theme->expects($this->once())->method('getFullPath')->will($this->returnValue($path)); - + $theme->expects($this->once())->method('getCode')->willReturn('Magento/luma'); $this->themeProviderMock->expects( $this->once() )->method( @@ -95,7 +95,6 @@ public function testCreateDummy() { $themeId = 0; $theme = $this->getMock(\Magento\Theme\Model\Theme::class, [], [], '', false); - $theme->expects($this->once())->method('getId')->will($this->returnValue($themeId)); $this->themeProviderMock->expects( $this->once() diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Design/Theme/Image/UploaderTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Design/Theme/Image/UploaderTest.php index 7a33830bc8cfb..66ceedc030d03 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Design/Theme/Image/UploaderTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Design/Theme/Image/UploaderTest.php @@ -1,6 +1,6 @@ scopeConfigMock = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); $this->requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false); + $this->serializerMock = $this->getMock(Json::class, [], [], '', false); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->designExceptions = $this->objectManagerHelper->getObject( @@ -39,32 +44,39 @@ protected function setUp() [ 'scopeConfig' => $this->scopeConfigMock, 'exceptionConfigPath' => $this->exceptionConfigPath, - 'scopeType' => $this->scopeType + 'scopeType' => $this->scopeType, + 'serializer' => $this->serializerMock, ] ); } /** * @param string $userAgent - * @param bool $useConfig + * @param bool $configValue + * @param int $callNum * @param bool|string $result * @param array $expressions * @dataProvider getThemeByRequestDataProvider */ - public function testGetThemeByRequest($userAgent, $useConfig, $result, $expressions = []) + public function testGetThemeByRequest($userAgent, $configValue, $callNum, $result, $expressions = []) { $this->requestMock->expects($this->once()) ->method('getServer') ->with($this->equalTo('HTTP_USER_AGENT')) ->will($this->returnValue($userAgent)); - if ($useConfig) { + if ($userAgent) { $this->scopeConfigMock->expects($this->once()) ->method('getValue') ->with($this->equalTo($this->exceptionConfigPath), $this->equalTo($this->scopeType)) - ->will($this->returnValue(serialize($expressions))); + ->will($this->returnValue($configValue)); } + $this->serializerMock->expects($this->exactly($callNum)) + ->method('unserialize') + ->with($configValue) + ->willReturn($expressions); + $this->assertSame($result, $this->designExceptions->getThemeByRequest($this->requestMock)); } @@ -74,11 +86,11 @@ public function testGetThemeByRequest($userAgent, $useConfig, $result, $expressi public function getThemeByRequestDataProvider() { return [ - [false, false, false], - ['iphone', false, false], - ['iphone', true, false], - ['iphone', true, 'matched', [['regexp' => '/iphone/', 'value' => 'matched']]], - ['explorer', true, false, [['regexp' => '/iphone/', 'value' => 'matched']]], + [false, null, 0, false], + ['iphone', null, 0, false], + ['iphone', 'serializedExpressions1', 1, false], + ['iphone', 'serializedExpressions2', 1, 'matched', [['regexp' => '/iphone/', 'value' => 'matched']]], + ['explorer', 'serializedExpressions3', 1, false, [['regexp' => '/iphone/', 'value' => 'matched']]], ]; } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/DesignLoaderTest.php b/lib/internal/Magento/Framework/View/Test/Unit/DesignLoaderTest.php index 58331e32deda4..9435c1a09e311 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/DesignLoaderTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/DesignLoaderTest.php @@ -1,6 +1,6 @@ block->setData('module_name', $moduleName); - $this->eventManagerMock->expects($this->once()) + $this->eventManagerMock->expects($this->exactly(2)) ->method('dispatch') - ->with('view_block_abstract_to_html_before', ['block' => $this->block]); - $this->scopeConfigMock->expects($this->once()) - ->method('getValue') - ->with('advanced/modules_disable_output/' . $moduleName, \Magento\Store\Model\ScopeInterface::SCOPE_STORE) - ->willReturn(true); + ->willReturnMap([ + ['view_block_abstract_to_html_before', ['block' => $this->block]], + ['view_block_abstract_to_html_after', ['block' => $this->block]], + ]); $this->assertSame('', $this->block->toHtml()); } @@ -219,6 +218,7 @@ public function testToHtmlWhenModuleIsDisabled() * @param string|bool $cacheLifetime * @param string|bool $dataFromCache * @param string $dataForSaveCache + * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsDispatchEvent * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsCacheLoad * @param \PHPUnit_Framework_MockObject_Matcher_InvokedCount $expectsCacheSave * @param string $expectedResult @@ -229,6 +229,7 @@ public function testGetCacheLifetimeViaToHtml( $cacheLifetime, $dataFromCache, $dataForSaveCache, + $expectsDispatchEvent, $expectsCacheLoad, $expectsCacheSave, $expectedResult @@ -239,13 +240,8 @@ public function testGetCacheLifetimeViaToHtml( $this->block->setData('module_name', $moduleName); $this->block->setData('cache_lifetime', $cacheLifetime); - $this->eventManagerMock->expects($this->once()) - ->method('dispatch') - ->with('view_block_abstract_to_html_before', ['block' => $this->block]); - $this->scopeConfigMock->expects($this->once()) - ->method('getValue') - ->with('advanced/modules_disable_output/' . $moduleName, \Magento\Store\Model\ScopeInterface::SCOPE_STORE) - ->willReturn(false); + $this->eventManagerMock->expects($expectsDispatchEvent) + ->method('dispatch'); $this->cacheStateMock->expects($this->any()) ->method('isEnabled') ->with(AbstractBlock::CACHE_GROUP) @@ -278,6 +274,7 @@ public function getCacheLifetimeDataProvider() 'cacheLifetime' => null, 'dataFromCache' => 'dataFromCache', 'dataForSaveCache' => '', + 'expectsDispatchEvent' => $this->exactly(2), 'expectsCacheLoad' => $this->never(), 'expectsCacheSave' => $this->never(), 'expectedResult' => '', @@ -286,6 +283,7 @@ public function getCacheLifetimeDataProvider() 'cacheLifetime' => false, 'dataFromCache' => 'dataFromCache', 'dataForSaveCache' => '', + 'expectsDispatchEvent' => $this->exactly(2), 'expectsCacheLoad' => $this->once(), 'expectsCacheSave' => $this->never(), 'expectedResult' => 'dataFromCache', @@ -294,6 +292,7 @@ public function getCacheLifetimeDataProvider() 'cacheLifetime' => 120, 'dataFromCache' => 'dataFromCache', 'dataForSaveCache' => '', + 'expectsDispatchEvent' => $this->exactly(2), 'expectsCacheLoad' => $this->once(), 'expectsCacheSave' => $this->never(), 'expectedResult' => 'dataFromCache', @@ -302,6 +301,7 @@ public function getCacheLifetimeDataProvider() 'cacheLifetime' => '120string', 'dataFromCache' => 'dataFromCache', 'dataForSaveCache' => '', + 'expectsDispatchEvent' => $this->exactly(2), 'expectsCacheLoad' => $this->once(), 'expectsCacheSave' => $this->never(), 'expectedResult' => 'dataFromCache', @@ -310,6 +310,7 @@ public function getCacheLifetimeDataProvider() 'cacheLifetime' => 120, 'dataFromCache' => false, 'dataForSaveCache' => '', + 'expectsDispatchEvent' => $this->exactly(2), 'expectsCacheLoad' => $this->once(), 'expectsCacheSave' => $this->once(), 'expectedResult' => '', diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/BlockFactoryTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/BlockFactoryTest.php index c430e8a31f756..19312ced6fad5 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/BlockFactoryTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/BlockFactoryTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\Event\ManagerInterface::class); $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); - $escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class) + $this->escaper = $this->getMockBuilder(\Magento\Framework\Escaper::class) ->disableOriginalConstructor() ->getMock(); - $escaper->expects($this->any()) - ->method('escapeHtml') - ->will($this->returnArgument(0)); $context = $this->getMockBuilder(\Magento\Framework\View\Element\Context::class) ->disableOriginalConstructor() ->getMock(); $context->expects($this->once()) ->method('getEscaper') - ->will($this->returnValue($escaper)); + ->will($this->returnValue($this->escaper)); $context->expects($this->once()) ->method('getEventManager') ->will($this->returnValue($eventManager)); @@ -92,8 +95,52 @@ public function testGetSetTitle() $this->assertEquals($selectTitle, $this->select->getTitle()); } + public function testGetHtmlJs() + { + $this->escaper->expects($this->any()) + ->method('escapeHtml') + ->will($this->returnArgument(0)); + $this->escaper->expects($this->any()) + ->method('escapeHtmlAttr') + ->will($this->returnArgument(0)); + + $selectId = 'testId'; + $selectClass = 'testClass'; + $selectTitle = 'testTitle'; + $selectName = 'testName'; + + $options = [ + 'testValue' => 'testLabel', + 'selectedValue' => 'selectedLabel', + ]; + $selectedValue = 'selectedValue'; + + $this->select->setId($selectId); + $this->select->setClass($selectClass); + $this->select->setTitle($selectTitle); + $this->select->setName($selectName); + $this->select->setOptions($options); + $this->select->setValue($selectedValue); + + $result = ''; + + $this->select->setIsRenderToJsTemplate(true); + $this->assertEquals($result, $this->select->getHtml()); + } + public function testGetHtml() { + $this->escaper->expects($this->any()) + ->method('escapeHtml') + ->will($this->returnArgument(0)); + $this->escaper->expects($this->any()) + ->method('escapeHtmlAttr') + ->will($this->returnArgument(0)); + $selectId = 'testId'; $selectClass = 'testClass'; $selectTitle = 'testTitle'; @@ -137,33 +184,112 @@ public function testGetHtml() $this->assertEquals($result, $this->select->getHtml()); } - public function testGetHtmlJs() + public function testGetHtmlEscapes() { - $selectId = 'testId'; - $selectClass = 'testClass'; - $selectTitle = 'testTitle'; - $selectName = 'testName'; + $this->escaper->expects($this->any()) + ->method('escapeHtml') + ->will($this->returnValue('ESCAPED')); + $this->escaper->expects($this->any()) + ->method('escapeHtmlAttr') + ->will($this->returnValue('ESCAPED_ATTR')); - $options = [ - 'testValue' => 'testLabel', - 'selectedValue' => 'selectedLabel', + $optionsSets = [ + $this->getOptionsWithSingleQuotes(), + $this->getOptionsWithDoubleQuotes() ]; - $selectedValue = 'selectedValue'; - - $this->select->setId($selectId); - $this->select->setClass($selectClass); - $this->select->setTitle($selectTitle); - $this->select->setName($selectName); - $this->select->setOptions($options); - $this->select->setValue($selectedValue); - $result = '' + . '' + . '' + . '' + . '' + . '' + . '' . ''; - $this->select->setIsRenderToJsTemplate(true); - $this->assertEquals($result, $this->select->getHtml()); + foreach ($optionsSets as $inOptions) { + $this->select->setId($inOptions['id']); + $this->select->setClass($inOptions['class']); + $this->select->setTitle($inOptions['title']); + $this->select->setName($inOptions['name']); + + foreach ($inOptions['options'] as $option) { + $this->select->addOption($option['value'], $option['label'], $option['params']); + } + $this->select->setValue($inOptions['values']); + + $this->assertEquals($expectedResult, $this->select->getHtml()); + + // reset + $this->select->setOptions([]); + } + } + + /** + * @return array + */ + private function getOptionsWithSingleQuotes() + { + return [ + 'id' => "testId", + 'name' => "test[name]", + 'class' => "test class", + 'title' => "test'Title", + 'options' => [ + 'regular' => [ + 'value' => 'testValue', + 'label' => "test'Label", + 'params' => ['paramKey' => "param'Value"] + ], + 'selected' => [ + 'value' => 'selectedValue', + 'label' => "selected'Label", + 'params' => [] + ], + 'optgroup' => [ + 'value' => [ + 'groupElementValue' => "GroupElement'Label", + 'selectedGroupElementValue' => "SelectedGroupElement'Label" + ], + 'label' => "group'Label", + 'params' => [] + ] + ], + 'values' => ['selectedValue', 'selectedGroupElementValue'] + ]; + } + + /** + * @return array + */ + private function getOptionsWithDoubleQuotes() + { + return [ + 'id' => 'testId', + 'name' => 'test[name]', + 'class' => 'test class', + 'title' => 'test"Title', + 'options' => [ + 'regular' => [ + 'value' => 'testValue', + 'label' => 'test"Label', + 'params' => ['paramKey' => 'param"Value'] + ], + 'selected' => [ + 'value' => 'selectedValue', + 'label' => 'selected"Label', + 'params' => [] + ], + 'optgroup' => [ + 'value' => [ + 'groupElementValue' => 'GroupElement"Label', + 'selectedGroupElementValue' => 'SelectedGroupElement"Label' + ], + 'label' => 'group"Label', + 'params' => [] + ] + ], + 'values' => ['selectedValue', 'selectedGroupElementValue'] + ]; } } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php index a5b24d8c0c323..1d5af35266edb 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Js/CookieTest.php @@ -1,6 +1,6 @@ entitySpecificHandlesList = $objectManager->getObject(EntitySpecificHandlesList::class); + } + + public function testAddAndGetHandles() + { + $this->assertEquals([], $this->entitySpecificHandlesList->getHandles()); + $this->entitySpecificHandlesList->addHandle('handle1'); + $this->entitySpecificHandlesList->addHandle('handle2'); + $this->assertEquals(['handle1', 'handle2'], $this->entitySpecificHandlesList->getHandles()); + } +} diff --git a/lib/internal/Magento/Framework/View/Test/Unit/File/Collector/BaseTest.php b/lib/internal/Magento/Framework/View/Test/Unit/File/Collector/BaseTest.php index 25b3bededf04d..ff6f3c94cadec 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/File/Collector/BaseTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/File/Collector/BaseTest.php @@ -1,6 +1,6 @@ self::EXPECTED_CLASS]; - $this->_objectManager->expects( - $this->once() - )->method( - 'create' - )->with( - self::EXPECTED_CLASS - )->will( - $this->returnValue($this) - ); + $input = ['name' => 'dataSource', 'value' => self::EXPECTED_CLASS]; + $this->_objectManager->expects($this->once()) + ->method('create') + ->with(self::EXPECTED_CLASS) + ->willReturn($this); $actual = $this->_model->evaluate($input); $this->assertSame($this, $actual); @@ -56,17 +51,18 @@ public function testEvaluateWrongClass($input, $expectedException, $expectedExce { $this->setExpectedException($expectedException, $expectedExceptionMessage); $self = $this; - $this->_objectManager->expects($this->any())->method('create')->will( - $this->returnCallback( - function ($className) use ($self) { - return $self->getMock($className); - } - ) + $this->_objectManager->expects($this->any())->method('create')->willReturnCallback( + function ($className) use ($self) { + return $self->getMock($className); + } ); $this->_model->evaluate($input); } + /** + * @return array + */ public function evaluateWrongClassDataProvider() { return [ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/OptionsTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/OptionsTest.php index 87bdef315a5c8..b2a30b5cb1290 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/OptionsTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Argument/Interpreter/OptionsTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/BuilderFactoryTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/BuilderFactoryTest.php index 6afd0ca712149..bbbc2f252b480 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/BuilderFactoryTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/BuilderFactoryTest.php @@ -1,6 +1,6 @@ scheduledStructure->expects($this->once()) + ->method('unsetElementFromListToRemove') + ->with($literal); + } + $this->context->expects($this->once())->method('getScheduledStructure') ->will($this->returnValue($this->scheduledStructure)); diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php index 4e10a5a6a0841..430ec56230f0b 100755 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/ContainerTest.php @@ -1,6 +1,6 @@ with($contextMock, $elementCurrent) ->willReturnSelf(); + if ($elementCurrent->getAttribute('remove') == 'false') { + $scheduledStructureMock->expects($this->once()) + ->method('unsetElementFromListToRemove') + ->with($elementCurrent->getAttribute('name')); + } + $this->container->interpret($contextMock, $elementCurrent); } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/FactoryTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/FactoryTest.php index a91ac3b38709d..a6608ad6c053c 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/FactoryTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/Reader/FactoryTest.php @@ -1,6 +1,6 @@ expects($this->once())->method('setStructureElementData')->with( $element->getAttribute('name'), - ['attributes' => ['group' => '', 'component' => 'listing']] + ['attributes' => ['group' => '', 'component' => 'listing', 'acl' => 'test', 'condition' => 'test']] ); $scheduleStructure->expects($this->once())->method('setElementToIfconfigList')->with( $element->getAttribute('name'), @@ -88,7 +88,12 @@ public function interpretDataProvider() return [ [ $this->getElement( - '', + '', 'uiComponent' ), ] diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php index 9dddead0e2af8..440218fb5376f 100755 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/ReaderPoolTest.php @@ -1,6 +1,6 @@ test test - \ No newline at end of file + diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/arguments.xml b/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/arguments.xml index 3be95e59dfa11..04b102f7aa0df 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/arguments.xml +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/arguments.xml @@ -1,7 +1,7 @@ @@ -33,7 +33,7 @@ Excel XML - Magento\Sales\Model\Order\Grid\Massaction\ItemsUpdater + Magento\Framework\View\Layout\Argument\UpdaterInterface Move to Archive */sales_archive/massAdd diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/invalidLayoutArgumentsXmlArray.php b/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/invalidLayoutArgumentsXmlArray.php index c6ec5526e4033..810692b94fa49 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/invalidLayoutArgumentsXmlArray.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Layout/_files/invalidLayoutArgumentsXmlArray.php @@ -1,6 +1,6 @@ structureMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Data\Structure::class) @@ -141,9 +158,22 @@ protected function setUp() $this->readerContextFactoryMock = $this->getMockBuilder( \Magento\Framework\View\Layout\Reader\ContextFactory::class )->disableOriginalConstructor()->getMock(); + + $this->pageConfigStructure = $this->getMockBuilder(\Magento\Framework\View\Page\Config\Structure::class) + ->setMethods(['__toArray', 'populateWithArray']) + ->getMock(); + $this->layoutScheduledSructure = $this->getMockBuilder(\Magento\Framework\View\Layout\ScheduledStructure::class) + ->setMethods(['__toArray', 'populateWithArray']) + ->getMock(); $this->readerContextMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Reader\Context::class) + ->setMethods(['getPageConfigStructure', 'getScheduledStructure']) ->disableOriginalConstructor() ->getMock(); + $this->readerContextMock->expects($this->any())->method('getPageConfigStructure') + ->willReturn($this->pageConfigStructure); + $this->readerContextMock->expects($this->any())->method('getScheduledStructure') + ->willReturn($this->layoutScheduledSructure); + $this->generatorContextFactoryMock = $this->getMockBuilder( \Magento\Framework\View\Layout\Generator\ContextFactory::class ) @@ -154,6 +184,15 @@ protected function setUp() ->getMock(); $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) ->getMock(); + $this->serializer = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class); + $this->serializer->expects($this->any())->method('serialize') + ->willReturnCallback(function ($value) { + return json_encode($value); + }); + $this->serializer->expects($this->any())->method('unserialize') + ->willReturnCallback(function ($value) { + return json_decode($value, true); + }); $this->model = new \Magento\Framework\View\Layout( $this->processorFactoryMock, @@ -168,7 +207,8 @@ protected function setUp() $this->generatorContextFactoryMock, $this->appStateMock, $this->loggerMock, - true + true, + $this->serializer ); } @@ -735,9 +775,32 @@ public function testGenerateElementsWithoutCache() ->with($this->readerContextMock, $xml) ->willReturnSelf(); + $pageConfigStructureData = [ + 'field_1' => 123, + 'field_2' => 'text', + 'field_3' => [ + 'field_3_1' => '1244', + 'field_3_2' => null, + 'field_3_3' => false, + ] + ]; + $this->pageConfigStructure->expects($this->any())->method('__toArray') + ->willReturn($pageConfigStructureData); + + $layoutScheduledStructureData = [ + 'field_1' => 1283, + 'field_2' => 'text_qwertyuiop[]asdfghjkl;' + ]; + $this->layoutScheduledSructure->expects($this->any())->method('__toArray') + ->willReturn($layoutScheduledStructureData); + $data = [ + 'pageConfigStructure' => $pageConfigStructureData, + 'scheduledStructure' => $layoutScheduledStructureData + ]; + $this->cacheMock->expects($this->once()) ->method('save') - ->with(serialize($this->readerContextMock), 'structure_' . $layoutCacheId, $handles) + ->with(json_encode($data), 'structure_' . $layoutCacheId, $handles) ->willReturn(true); $generatorContextMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Generator\Context::class) @@ -774,6 +837,9 @@ public function testGenerateElementsWithCache() $xml = simplexml_load_string('', \Magento\Framework\View\Layout\Element::class); $this->model->setXml($xml); + $this->readerContextFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->readerContextMock); $themeMock = $this->getMockForAbstractClass(\Magento\Framework\View\Design\ThemeInterface::class); $this->themeResolverMock->expects($this->once()) ->method('get') @@ -787,14 +853,33 @@ public function testGenerateElementsWithCache() ->method('getCacheId') ->willReturn($layoutCacheId); - $readerContextMock = $this->getMockBuilder(\Magento\Framework\View\Layout\Reader\Context::class) - ->disableOriginalConstructor() - ->getMock(); + $pageConfigStructureData = [ + 'field_1' => 123, + 'field_2' => 'text', + 'field_3' => [ + 'field_3_1' => '1244', + 'field_3_2' => null, + 'field_3_3' => false, + ] + ]; + $this->pageConfigStructure->expects($this->once())->method('populateWithArray') + ->with($pageConfigStructureData); + + $layoutScheduledStructureData = [ + 'field_1' => 1283, + 'field_2' => 'text_qwertyuiop[]asdfghjkl;' + ]; + $this->layoutScheduledSructure->expects($this->once())->method('populateWithArray') + ->with($layoutScheduledStructureData); + $data = [ + 'pageConfigStructure' => $pageConfigStructureData, + 'scheduledStructure' => $layoutScheduledStructureData + ]; $this->cacheMock->expects($this->once()) ->method('load') ->with('structure_' . $layoutCacheId) - ->willReturn(serialize($readerContextMock)); + ->willReturn(json_encode($data)); $this->readerPoolMock->expects($this->never()) ->method('interpret'); @@ -811,7 +896,7 @@ public function testGenerateElementsWithCache() $this->generatorPoolMock->expects($this->once()) ->method('process') - ->with($readerContextMock, $generatorContextMock) + ->with($this->readerContextMock, $generatorContextMock) ->willReturn(true); $elements = [ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Model/Layout/MergeTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Model/Layout/MergeTest.php index 561c48b915de3..48fdff2fe0960 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Model/Layout/MergeTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Model/Layout/MergeTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_head.xml b/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_head.xml index 9ed7ae97f18e7..27c6a73879a0f 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_head.xml +++ b/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_head.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_html.xml b/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_html.xml index b6e011039ff89..35c4306ee74a5 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_html.xml +++ b/lib/internal/Magento/Framework/View/Test/Unit/Page/Config/_files/template_html.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Page/ConfigTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Page/ConfigTest.php index 32f319f51c732..9ae9241e739f8 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Page/ConfigTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Page/ConfigTest.php @@ -1,6 +1,6 @@ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/PageLayout/_files/layouts_two.xml b/lib/internal/Magento/Framework/View/Test/Unit/PageLayout/_files/layouts_two.xml index 285dd37a4c2b4..6103558052070 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/PageLayout/_files/layouts_two.xml +++ b/lib/internal/Magento/Framework/View/Test/Unit/PageLayout/_files/layouts_two.xml @@ -1,7 +1,7 @@ diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Render/RenderFactoryTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Render/RenderFactoryTest.php index 0ae4cf420a4ec..ea88eb9f10889 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Render/RenderFactoryTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Render/RenderFactoryTest.php @@ -1,6 +1,6 @@ with(['pageConfig' => $this->pageConfig]) ->willReturn($this->pageConfigRenderer); + $this->entitySpecificHandlesListMock = $this->getMock(EntitySpecificHandlesList::class, [], [], '', false); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->page = $objectManagerHelper->getObject( \Magento\Framework\View\Result\Page::class, @@ -128,6 +136,7 @@ protected function setUp() 'context' => $this->context, 'translateInline' => $this->translateInline, 'pageConfigRendererFactory' => $pageConfigRendererFactory, + 'entitySpecificHandlesList' => $this->entitySpecificHandlesListMock ] ); } @@ -221,9 +230,41 @@ public function testAddPageLayoutHandles() ->with($expected) ->willReturnSelf(); + $this->entitySpecificHandlesListMock->expects($this->at(0)) + ->method('addHandle')->with('full_action_name_key_one_val_one'); + $this->entitySpecificHandlesListMock->expects($this->at(1)) + ->method('addHandle')->with('full_action_name_key_two_val_two'); + $this->page->addPageLayoutHandles($parameters, $defaultHandle); } + public function testAddPageLayoutHandlesNotEntitySpecific() + { + $fullActionName = 'Full_Action_Name'; + $defaultHandle = null; + $parameters = [ + 'key_one' => 'val_one', + 'key_two' => 'val_two', + ]; + $expected = [ + 'full_action_name', + 'full_action_name_key_one_val_one', + 'full_action_name_key_two_val_two', + ]; + $this->request->expects($this->any()) + ->method('getFullActionName') + ->will($this->returnValue($fullActionName)); + + $this->layoutMerge->expects($this->any()) + ->method('addHandle') + ->with($expected) + ->willReturnSelf(); + + $this->entitySpecificHandlesListMock->expects($this->never())->method('addHandle'); + + $this->page->addPageLayoutHandles($parameters, $defaultHandle, false); + } + public function testAddPageLayoutHandlesWithDefaultHandle() { $defaultHandle = 'default_handle'; diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Template/Html/MinifierTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Template/Html/MinifierTest.php index fb921f3776b9b..0ab955a06f896 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Template/Html/MinifierTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Template/Html/MinifierTest.php @@ -1,6 +1,6 @@ @@ -160,7 +160,7 @@ public function testMinify() TEXT; $expectedContent = << Test titleText Link some textsomeMethod(); ?>
    +
    + Snippet: +
    escapeHtml(__('Wish List')); ?>
    escapeHtml(__('Product')) ?>escapeHtml(__('Comment')) ?>escapeHtml(__('Add to Cart')) ?>
    + getImage($product, 'customer_shared_wishlist')->toHtml(); ?> @@ -47,20 +47,20 @@ ?> getDetailsHtml($item) ?> getEscapedDescription($item) ?> + getEscapedDescription($item) ?> isSaleable()): ?> - + escapeHtml(__('Add to Wish List')) ?>
    + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveHowSourceRendered
    ng-bind-htmlAutomatically uses $sanitize
    <div ng-bind-html="snippet">
    </div>
    ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value +
    <div ng-bind-html="deliberatelyTrustDangerousSnippet()">
    +     </div>
    +
    ng-bindAutomatically escapes
    <div ng-bind="snippet">
    </div>
    +
    + + + it('should sanitize the html snippet by default', function() { + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('

    an html\nclick here\nsnippet

    '); + }); + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()). + toBe("

    an html\n" + + "click here\n" + + "snippet

    "); + }); + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getInnerHtml()). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +
    + + */ + function $SanitizeProvider() { + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; + } + + function sanitizeText(chars) { + var buf = []; + var writer = htmlSanitizeWriter(buf, angular.noop); + writer.chars(chars); + return buf.join(''); + } + + +// Regular Expressions for parsing tags and attributes + var START_TAG_REGEXP = + /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/, + END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/, + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, + BEGIN_TAG_REGEXP = /^/g, + DOCTYPE_REGEXP = /]*?)>/i, + CDATA_REGEXP = //g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; + + +// Good source of info about elements and attributes +// http://dev.w3.org/html5/spec/Overview.html#semantics +// http://simon.html5.org/html-elements + +// Safe Void Elements - HTML5 +// http://dev.w3.org/html5/spec/Overview.html#void-elements + var voidElements = makeMap("area,br,col,hr,img,wbr"); + +// Elements that you can, intentionally, leave open (and which close themselves) +// http://dev.w3.org/html5/spec/Overview.html#optional-tags + var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), + optionalEndTagInlineElements = makeMap("rp,rt"), + optionalEndTagElements = angular.extend({}, + optionalEndTagInlineElements, + optionalEndTagBlockElements); + +// Safe Block Elements - HTML5 + var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," + + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); + +// Inline Elements - HTML5 + var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," + + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + + "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); + + +// Special Elements (can contain anything) + var specialElements = makeMap("script,style"); + + var validElements = angular.extend({}, + voidElements, + blockElements, + inlineElements, + optionalEndTagElements); + +//Attributes that have href and hence need to be sanitized + var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap"); + var validAttrs = angular.extend({}, uriAttrs, makeMap( + 'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+ + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+ + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+ + 'scope,scrolling,shape,size,span,start,summary,target,title,type,'+ + 'valign,value,vspace,width')); + + function makeMap(str) { + var obj = {}, items = str.split(','), i; + for (i = 0; i < items.length; i++) obj[items[i]] = true; + return obj; + } + + + /** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ + function htmlParser( html, handler ) { + var index, chars, match, stack = [], last = html; + stack.last = function() { return stack[ stack.length - 1 ]; }; + + while ( html ) { + chars = true; + + // Make sure we're not in a script or style element + if ( !stack.last() || !specialElements[ stack.last() ] ) { + + // Comment + if ( html.indexOf("", index) === index) { + if (handler.comment) handler.comment( html.substring( 4, index ) ); + html = html.substring( index + 3 ); + chars = false; + } + // DOCTYPE + } else if ( DOCTYPE_REGEXP.test(html) ) { + match = html.match( DOCTYPE_REGEXP ); + + if ( match ) { + html = html.replace( match[0] , ''); + chars = false; + } + // end tag + } else if ( BEGING_END_TAGE_REGEXP.test(html) ) { + match = html.match( END_TAG_REGEXP ); + + if ( match ) { + html = html.substring( match[0].length ); + match[0].replace( END_TAG_REGEXP, parseEndTag ); + chars = false; + } + + // start tag + } else if ( BEGIN_TAG_REGEXP.test(html) ) { + match = html.match( START_TAG_REGEXP ); + + if ( match ) { + html = html.substring( match[0].length ); + match[0].replace( START_TAG_REGEXP, parseStartTag ); + chars = false; + } + } + + if ( chars ) { + index = html.indexOf("<"); + + var text = index < 0 ? html : html.substring( 0, index ); + html = index < 0 ? "" : html.substring( index ); + + if (handler.chars) handler.chars( decodeEntities(text) ); + } + + } else { + html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), + function(all, text){ + text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); + + if (handler.chars) handler.chars( decodeEntities(text) ); + + return ""; + }); + + parseEndTag( "", stack.last() ); + } + + if ( html == last ) { + throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + + "of html: {0}", html); + } + last = html; + } + + // Clean up any remaining tags + parseEndTag(); + + function parseStartTag( tag, tagName, rest, unary ) { + tagName = angular.lowercase(tagName); + if ( blockElements[ tagName ] ) { + while ( stack.last() && inlineElements[ stack.last() ] ) { + parseEndTag( "", stack.last() ); + } + } + + if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) { + parseEndTag( "", tagName ); + } + + unary = voidElements[ tagName ] || !!unary; + + if ( !unary ) + stack.push( tagName ); + + var attrs = {}; + + rest.replace(ATTR_REGEXP, + function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { + var value = doubleQuotedValue + || singleQuotedValue + || unquotedValue + || ''; + + attrs[name] = decodeEntities(value); + }); + if (handler.start) handler.start( tagName, attrs, unary ); + } + + function parseEndTag( tag, tagName ) { + var pos = 0, i; + tagName = angular.lowercase(tagName); + if ( tagName ) + // Find the closest opened tag of the same type + for ( pos = stack.length - 1; pos >= 0; pos-- ) + if ( stack[ pos ] == tagName ) + break; + + if ( pos >= 0 ) { + // Close all the open elements, up the stack + for ( i = stack.length - 1; i >= pos; i-- ) + if (handler.end) handler.end( stack[ i ] ); + + // Remove the open elements from the stack + stack.length = pos; + } + } + } + + var hiddenPre=document.createElement("pre"); + var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; + /** + * decodes all entities into regular string + * @param value + * @returns {string} A string with decoded entities. + */ + function decodeEntities(value) { + if (!value) { return ''; } + + // Note: IE8 does not preserve spaces at the start/end of innerHTML + // so we must capture them and reattach them afterward + var parts = spaceRe.exec(value); + var spaceBefore = parts[1]; + var spaceAfter = parts[3]; + var content = parts[2]; + if (content) { + hiddenPre.innerHTML=content.replace(//g, '>'); + } + + /** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.jain('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ + function htmlSanitizeWriter(buf, uriValidator){ + var ignore = false; + var out = angular.bind(buf, buf.push); + return { + start: function(tag, attrs, unary){ + tag = angular.lowercase(tag); + if (!ignore && specialElements[tag]) { + ignore = tag; + } + if (!ignore && validElements[tag] === true) { + out('<'); + out(tag); + angular.forEach(attrs, function(value, key){ + var lkey=angular.lowercase(key); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out(unary ? '/>' : '>'); + } + }, + end: function(tag){ + tag = angular.lowercase(tag); + if (!ignore && validElements[tag] === true) { + out(''); + } + if (tag == ignore) { + ignore = false; + } + }, + chars: function(chars){ + if (!ignore) { + out(encodeEntities(chars)); + } + } + }; + } + + +// define ngSanitize module and register $sanitize service + angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); + + /* global sanitizeText: false */ + + /** + * @ngdoc filter + * @name linky + * @function + * + * @description + * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and + * plain email address links. + * + * Requires the {@link ngSanitize `ngSanitize`} module to be installed. + * + * @param {string} text Input text. + * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in. + * @returns {string} Html-linkified text. + * + * @usage + + * + * @example + + + +
    + Snippet: + + + + + + + + + + + + + + + + + + + + + +
    FilterSourceRendered
    linky filter +
    <div ng-bind-html="snippet | linky">
    </div>
    +
    +
    +
    linky target +
    <div ng-bind-html="snippetWithTarget | linky:'_blank'">
    </div>
    +
    +
    +
    no filter
    <div ng-bind="snippet">
    </div>
    + + + it('should linkify the snippet with urls', function() { + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); + }); + it('should not linkify snippet without the linky filter', function() { + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); + }); + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new http://link.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('new http://link.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) + .toBe('new http://link.'); + }); + it('should work with the target property', function() { + expect(element(by.id('linky-target')). + element(by.binding("snippetWithTarget | linky:'_blank'")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); + }); + + + */ + angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { + var LINKY_URL_REGEXP = + /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/, + MAILTO_REGEXP = /^mailto:/; + + return function(text, target) { + if (!text) return text; + var match; + var raw = text; + var html = []; + var url; + var i; + while ((match = raw.match(LINKY_URL_REGEXP))) { + // We can not end in these as they are sometimes found at the end of the sentence + url = match[0]; + // if we did not match ftp/http/mailto then assume mailto + if (match[2] == match[3]) url = 'mailto:' + url; + i = match.index; + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); + raw = raw.substring(i + match[0].length); + } + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + html.push(''); + addText(text); + html.push(''); + } + }; + }]); + + +})(window, window.angular); \ No newline at end of file diff --git a/setup/pub/angular-sanitize/angular-sanitize.min.js.map b/setup/pub/angular-sanitize/angular-sanitize.min.js.map new file mode 100644 index 0000000000000..0c993a6ed2afb --- /dev/null +++ b/setup/pub/angular-sanitize/angular-sanitize.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-sanitize.min.js", +"lineCount":13, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAiJtCC,QAASA,EAAY,CAACC,CAAD,CAAQ,CAC3B,IAAIC,EAAM,EACGC,EAAAC,CAAmBF,CAAnBE,CAAwBN,CAAAO,KAAxBD,CACbH,MAAA,CAAaA,CAAb,CACA,OAAOC,EAAAI,KAAA,CAAS,EAAT,CAJoB,CAmE7BC,QAASA,EAAO,CAACC,CAAD,CAAM,CAAA,IAChBC,EAAM,EAAIC,EAAAA,CAAQF,CAAAG,MAAA,CAAU,GAAV,CAAtB,KAAsCC,CACtC,KAAKA,CAAL,CAAS,CAAT,CAAYA,CAAZ,CAAgBF,CAAAG,OAAhB,CAA8BD,CAAA,EAA9B,CAAmCH,CAAA,CAAIC,CAAA,CAAME,CAAN,CAAJ,CAAA,CAAgB,CAAA,CACnD,OAAOH,EAHa,CAmBtBK,QAASA,EAAU,CAAEC,CAAF,CAAQC,CAAR,CAAkB,CAiFnCC,QAASA,EAAa,CAAEC,CAAF,CAAOC,CAAP,CAAgBC,CAAhB,CAAsBC,CAAtB,CAA8B,CAClDF,CAAA,CAAUrB,CAAAwB,UAAA,CAAkBH,CAAlB,CACV,IAAKI,CAAA,CAAeJ,CAAf,CAAL,CACE,IAAA,CAAQK,CAAAC,KAAA,EAAR,EAAwBC,CAAA,CAAgBF,CAAAC,KAAA,EAAhB,CAAxB,CAAA,CACEE,CAAA,CAAa,EAAb,CAAiBH,CAAAC,KAAA,EAAjB,CAICG,EAAA,CAAwBT,CAAxB,CAAL,EAA0CK,CAAAC,KAAA,EAA1C,EAA0DN,CAA1D,EACEQ,CAAA,CAAa,EAAb,CAAiBR,CAAjB,CAKF,EAFAE,CAEA,CAFQQ,CAAA,CAAcV,CAAd,CAER,EAFmC,CAAC,CAACE,CAErC,GACEG,CAAAM,KAAA,CAAYX,CAAZ,CAEF,KAAIY,EAAQ,EAEZX,EAAAY,QAAA,CAAaC,CAAb,CACE,QAAQ,CAACC,CAAD,CAAQC,CAAR,CAAcC,CAAd,CAAiCC,CAAjC,CAAoDC,CAApD,CAAmE,CAMzEP,CAAA,CAAMI,CAAN,CAAA,CAAcI,CAAA,CALFH,CAKE,EAJTC,CAIS,EAHTC,CAGS,EAFT,EAES,CAN2D,CAD7E,CASItB,EAAAwB,MAAJ,EAAmBxB,CAAAwB,MAAA,CAAerB,CAAf,CAAwBY,CAAxB,CAA+BV,CAA/B,CA5B+B,CA+BpDM,QAASA,EAAW,CAAET,CAAF,CAAOC,CAAP,CAAiB,CAAA,IAC/BsB,EAAM,CADyB,CACtB7B,CAEb,IADAO,CACA,CADUrB,CAAAwB,UAAA,CAAkBH,CAAlB,CACV,CAEE,IAAMsB,CAAN,CAAYjB,CAAAX,OAAZ,CAA2B,CAA3B,CAAqC,CAArC,EAA8B4B,CAA9B,EACOjB,CAAA,CAAOiB,CAAP,CADP,EACuBtB,CADvB,CAAwCsB,CAAA,EAAxC;AAIF,GAAY,CAAZ,EAAKA,CAAL,CAAgB,CAEd,IAAM7B,CAAN,CAAUY,CAAAX,OAAV,CAAyB,CAAzB,CAA4BD,CAA5B,EAAiC6B,CAAjC,CAAsC7B,CAAA,EAAtC,CACMI,CAAA0B,IAAJ,EAAiB1B,CAAA0B,IAAA,CAAalB,CAAA,CAAOZ,CAAP,CAAb,CAGnBY,EAAAX,OAAA,CAAe4B,CAND,CATmB,CAhHF,IAC/BE,CAD+B,CACxB1C,CADwB,CACVuB,EAAQ,EADE,CACEC,EAAOV,CAG5C,KAFAS,CAAAC,KAEA,CAFamB,QAAQ,EAAG,CAAE,MAAOpB,EAAA,CAAOA,CAAAX,OAAP,CAAsB,CAAtB,CAAT,CAExB,CAAQE,CAAR,CAAA,CAAe,CACbd,CAAA,CAAQ,CAAA,CAGR,IAAMuB,CAAAC,KAAA,EAAN,EAAuBoB,CAAA,CAAiBrB,CAAAC,KAAA,EAAjB,CAAvB,CAmDEV,CASA,CATOA,CAAAiB,QAAA,CAAiBc,MAAJ,CAAW,kBAAX,CAAgCtB,CAAAC,KAAA,EAAhC,CAA+C,QAA/C,CAAyD,GAAzD,CAAb,CACL,QAAQ,CAACsB,CAAD,CAAMC,CAAN,CAAW,CACjBA,CAAA,CAAOA,CAAAhB,QAAA,CAAaiB,CAAb,CAA6B,IAA7B,CAAAjB,QAAA,CAA2CkB,CAA3C,CAAyD,IAAzD,CAEHlC,EAAAf,MAAJ,EAAmBe,CAAAf,MAAA,CAAesC,CAAA,CAAeS,CAAf,CAAf,CAEnB,OAAO,EALU,CADd,CASP,CAAArB,CAAA,CAAa,EAAb,CAAiBH,CAAAC,KAAA,EAAjB,CA5DF,KAAyD,CAGvD,GAA8B,CAA9B,GAAKV,CAAAoC,QAAA,CAAa,SAAb,CAAL,CAEER,CAEA,CAFQ5B,CAAAoC,QAAA,CAAa,IAAb,CAAmB,CAAnB,CAER,CAAc,CAAd,EAAKR,CAAL,EAAmB5B,CAAAqC,YAAA,CAAiB,QAAjB,CAAwBT,CAAxB,CAAnB,GAAsDA,CAAtD,GACM3B,CAAAqC,QAEJ,EAFqBrC,CAAAqC,QAAA,CAAiBtC,CAAAuC,UAAA,CAAgB,CAAhB,CAAmBX,CAAnB,CAAjB,CAErB,CADA5B,CACA,CADOA,CAAAuC,UAAA,CAAgBX,CAAhB,CAAwB,CAAxB,CACP,CAAA1C,CAAA,CAAQ,CAAA,CAHV,CAJF,KAUO,IAAKsD,CAAAC,KAAA,CAAoBzC,CAApB,CAAL,CAGL,IAFAmB,CAEA,CAFQnB,CAAAmB,MAAA,CAAYqB,CAAZ,CAER,CACExC,CACA;AADOA,CAAAiB,QAAA,CAAcE,CAAA,CAAM,CAAN,CAAd,CAAyB,EAAzB,CACP,CAAAjC,CAAA,CAAQ,CAAA,CAFV,CAHK,IAQA,IAAKwD,CAAAD,KAAA,CAA4BzC,CAA5B,CAAL,CAGL,IAFAmB,CAEA,CAFQnB,CAAAmB,MAAA,CAAYwB,CAAZ,CAER,CACE3C,CAEA,CAFOA,CAAAuC,UAAA,CAAgBpB,CAAA,CAAM,CAAN,CAAArB,OAAhB,CAEP,CADAqB,CAAA,CAAM,CAAN,CAAAF,QAAA,CAAkB0B,CAAlB,CAAkC/B,CAAlC,CACA,CAAA1B,CAAA,CAAQ,CAAA,CAHV,CAHK,IAUK0D,EAAAH,KAAA,CAAsBzC,CAAtB,CAAL,GACLmB,CADK,CACGnB,CAAAmB,MAAA,CAAY0B,CAAZ,CADH,IAIH7C,CAEA,CAFOA,CAAAuC,UAAA,CAAgBpB,CAAA,CAAM,CAAN,CAAArB,OAAhB,CAEP,CADAqB,CAAA,CAAM,CAAN,CAAAF,QAAA,CAAkB4B,CAAlB,CAAoC3C,CAApC,CACA,CAAAhB,CAAA,CAAQ,CAAA,CANL,CAUFA,EAAL,GACE0C,CAKA,CALQ5B,CAAAoC,QAAA,CAAa,GAAb,CAKR,CAHIH,CAGJ,CAHmB,CAAR,CAAAL,CAAA,CAAY5B,CAAZ,CAAmBA,CAAAuC,UAAA,CAAgB,CAAhB,CAAmBX,CAAnB,CAG9B,CAFA5B,CAEA,CAFe,CAAR,CAAA4B,CAAA,CAAY,EAAZ,CAAiB5B,CAAAuC,UAAA,CAAgBX,CAAhB,CAExB,CAAI3B,CAAAf,MAAJ,EAAmBe,CAAAf,MAAA,CAAesC,CAAA,CAAeS,CAAf,CAAf,CANrB,CAzCuD,CA+DzD,GAAKjC,CAAL,EAAaU,CAAb,CACE,KAAMoC,EAAA,CAAgB,UAAhB,CAC4C9C,CAD5C,CAAN,CAGFU,CAAA,CAAOV,CAvEM,CA2EfY,CAAA,EA/EmC,CA2IrCY,QAASA,EAAc,CAACuB,CAAD,CAAQ,CAC7B,GAAI,CAACA,CAAL,CAAc,MAAO,EAIrB,KAAIC,EAAQC,CAAAC,KAAA,CAAaH,CAAb,CACRI,EAAAA,CAAcH,CAAA,CAAM,CAAN,CAClB,KAAII,EAAaJ,CAAA,CAAM,CAAN,CAEjB,IADIK,CACJ,CADcL,CAAA,CAAM,CAAN,CACd,CACEM,CAAAC,UAKA,CALoBF,CAAApC,QAAA,CAAgB,IAAhB,CAAqB,MAArB,CAKpB,CAAAoC,CAAA,CAAU,aAAA,EAAiBC,EAAjB,CACRA,CAAAE,YADQ,CACgBF,CAAAG,UAE5B,OAAON,EAAP,CAAqBE,CAArB,CAA+BD,CAlBF,CA4B/BM,QAASA,EAAc,CAACX,CAAD,CAAQ,CAC7B,MAAOA,EAAA9B,QAAA,CACG,IADH;AACS,OADT,CAAAA,QAAA,CAEG0C,CAFH,CAE4B,QAAQ,CAACZ,CAAD,CAAO,CAC9C,MAAO,IAAP,CAAcA,CAAAa,WAAA,CAAiB,CAAjB,CAAd,CAAoC,GADU,CAF3C,CAAA3C,QAAA,CAKG,IALH,CAKS,MALT,CAAAA,QAAA,CAMG,IANH,CAMS,MANT,CADsB,CAoB/B7B,QAASA,EAAkB,CAACD,CAAD,CAAM0E,CAAN,CAAmB,CAC5C,IAAIC,EAAS,CAAA,CAAb,CACIC,EAAMhF,CAAAiF,KAAA,CAAa7E,CAAb,CAAkBA,CAAA4B,KAAlB,CACV,OAAO,OACEU,QAAQ,CAACtB,CAAD,CAAMa,CAAN,CAAaV,CAAb,CAAmB,CAChCH,CAAA,CAAMpB,CAAAwB,UAAA,CAAkBJ,CAAlB,CACD2D,EAAAA,CAAL,EAAehC,CAAA,CAAgB3B,CAAhB,CAAf,GACE2D,CADF,CACW3D,CADX,CAGK2D,EAAL,EAAsC,CAAA,CAAtC,GAAeG,CAAA,CAAc9D,CAAd,CAAf,GACE4D,CAAA,CAAI,GAAJ,CAcA,CAbAA,CAAA,CAAI5D,CAAJ,CAaA,CAZApB,CAAAmF,QAAA,CAAgBlD,CAAhB,CAAuB,QAAQ,CAAC+B,CAAD,CAAQoB,CAAR,CAAY,CACzC,IAAIC,EAAKrF,CAAAwB,UAAA,CAAkB4D,CAAlB,CAAT,CACIE,EAAmB,KAAnBA,GAAWlE,CAAXkE,EAAqC,KAArCA,GAA4BD,CAA5BC,EAAyD,YAAzDA,GAAgDD,CAC3B,EAAA,CAAzB,GAAIE,CAAA,CAAWF,CAAX,CAAJ,EACsB,CAAA,CADtB,GACGG,CAAA,CAASH,CAAT,CADH,EAC8B,CAAAP,CAAA,CAAad,CAAb,CAAoBsB,CAApB,CAD9B,GAEEN,CAAA,CAAI,GAAJ,CAIA,CAHAA,CAAA,CAAII,CAAJ,CAGA,CAFAJ,CAAA,CAAI,IAAJ,CAEA,CADAA,CAAA,CAAIL,CAAA,CAAeX,CAAf,CAAJ,CACA,CAAAgB,CAAA,CAAI,GAAJ,CANF,CAHyC,CAA3C,CAYA,CAAAA,CAAA,CAAIzD,CAAA,CAAQ,IAAR,CAAe,GAAnB,CAfF,CALgC,CAD7B,KAwBAqB,QAAQ,CAACxB,CAAD,CAAK,CACdA,CAAA,CAAMpB,CAAAwB,UAAA,CAAkBJ,CAAlB,CACD2D,EAAL,EAAsC,CAAA,CAAtC,GAAeG,CAAA,CAAc9D,CAAd,CAAf,GACE4D,CAAA,CAAI,IAAJ,CAEA,CADAA,CAAA,CAAI5D,CAAJ,CACA,CAAA4D,CAAA,CAAI,GAAJ,CAHF,CAKI5D,EAAJ,EAAW2D,CAAX,GACEA,CADF,CACW,CAAA,CADX,CAPc,CAxBb,OAmCE5E,QAAQ,CAACA,CAAD,CAAO,CACb4E,CAAL;AACEC,CAAA,CAAIL,CAAA,CAAexE,CAAf,CAAJ,CAFgB,CAnCjB,CAHqC,CAha9C,IAAI4D,EAAkB/D,CAAAyF,SAAA,CAAiB,WAAjB,CAAtB,CAwJI3B,EACG,4FAzJP,CA0JEF,EAAiB,2BA1JnB,CA2JEzB,EAAc,yEA3JhB,CA4JE0B,EAAmB,IA5JrB,CA6JEF,EAAyB,SA7J3B,CA8JER,EAAiB,qBA9JnB,CA+JEM,EAAiB,qBA/JnB,CAgKEL,EAAe,yBAhKjB,CAkKEwB,EAA0B,gBAlK5B,CA2KI7C,EAAetB,CAAA,CAAQ,wBAAR,CAIfiF,EAAAA,CAA8BjF,CAAA,CAAQ,gDAAR,CAC9BkF,EAAAA,CAA+BlF,CAAA,CAAQ,OAAR,CADnC,KAEIqB,EAAyB9B,CAAA4F,OAAA,CAAe,EAAf,CACeD,CADf,CAEeD,CAFf,CAF7B,CAOIjE,EAAgBzB,CAAA4F,OAAA,CAAe,EAAf,CAAmBF,CAAnB,CAAgDjF,CAAA,CAAQ,4KAAR,CAAhD,CAPpB;AAYImB,EAAiB5B,CAAA4F,OAAA,CAAe,EAAf,CAAmBD,CAAnB,CAAiDlF,CAAA,CAAQ,2JAAR,CAAjD,CAZrB,CAkBIsC,EAAkBtC,CAAA,CAAQ,cAAR,CAlBtB,CAoBIyE,EAAgBlF,CAAA4F,OAAA,CAAe,EAAf,CACe7D,CADf,CAEeN,CAFf,CAGeG,CAHf,CAIeE,CAJf,CApBpB,CA2BI0D,EAAW/E,CAAA,CAAQ,0CAAR,CA3Bf,CA4BI8E,EAAavF,CAAA4F,OAAA,CAAe,EAAf,CAAmBJ,CAAnB,CAA6B/E,CAAA,CAC1C,ySAD0C,CAA7B,CA5BjB;AA0LI8D,EAAUsB,QAAAC,cAAA,CAAuB,KAAvB,CA1Ld,CA2LI5B,EAAU,wBAsGdlE,EAAA+F,OAAA,CAAe,YAAf,CAA6B,EAA7B,CAAAC,SAAA,CAA0C,WAA1C,CA7UAC,QAA0B,EAAG,CAC3B,IAAAC,KAAA,CAAY,CAAC,eAAD,CAAkB,QAAQ,CAACC,CAAD,CAAgB,CACpD,MAAO,SAAQ,CAAClF,CAAD,CAAO,CACpB,IAAIb,EAAM,EACVY,EAAA,CAAWC,CAAX,CAAiBZ,CAAA,CAAmBD,CAAnB,CAAwB,QAAQ,CAACgG,CAAD,CAAMd,CAAN,CAAe,CAC9D,MAAO,CAAC,SAAA5B,KAAA,CAAeyC,CAAA,CAAcC,CAAd,CAAmBd,CAAnB,CAAf,CADsD,CAA/C,CAAjB,CAGA,OAAOlF,EAAAI,KAAA,CAAS,EAAT,CALa,CAD8B,CAA1C,CADe,CA6U7B,CAuGAR,EAAA+F,OAAA,CAAe,YAAf,CAAAM,OAAA,CAAoC,OAApC,CAA6C,CAAC,WAAD,CAAc,QAAQ,CAACC,CAAD,CAAY,CAAA,IACzEC,EACE,mEAFuE,CAGzEC,EAAgB,UAEpB,OAAO,SAAQ,CAACtD,CAAD,CAAOuD,CAAP,CAAe,CAoB5BC,QAASA,EAAO,CAACxD,CAAD,CAAO,CAChBA,CAAL,EAGAjC,CAAAe,KAAA,CAAU9B,CAAA,CAAagD,CAAb,CAAV,CAJqB,CAOvByD,QAASA,EAAO,CAACC,CAAD,CAAM1D,CAAN,CAAY,CAC1BjC,CAAAe,KAAA,CAAU,KAAV,CACIhC,EAAA6G,UAAA,CAAkBJ,CAAlB,CAAJ;CACExF,CAAAe,KAAA,CAAU,UAAV,CAEA,CADAf,CAAAe,KAAA,CAAUyE,CAAV,CACA,CAAAxF,CAAAe,KAAA,CAAU,IAAV,CAHF,CAKAf,EAAAe,KAAA,CAAU,QAAV,CACAf,EAAAe,KAAA,CAAU4E,CAAV,CACA3F,EAAAe,KAAA,CAAU,IAAV,CACA0E,EAAA,CAAQxD,CAAR,CACAjC,EAAAe,KAAA,CAAU,MAAV,CAX0B,CA1B5B,GAAI,CAACkB,CAAL,CAAW,MAAOA,EAMlB,KALA,IAAId,CAAJ,CACI0E,EAAM5D,CADV,CAEIjC,EAAO,EAFX,CAGI2F,CAHJ,CAII9F,CACJ,CAAQsB,CAAR,CAAgB0E,CAAA1E,MAAA,CAAUmE,CAAV,CAAhB,CAAA,CAEEK,CAMA,CANMxE,CAAA,CAAM,CAAN,CAMN,CAJIA,CAAA,CAAM,CAAN,CAIJ,EAJgBA,CAAA,CAAM,CAAN,CAIhB,GAJ0BwE,CAI1B,CAJgC,SAIhC,CAJ4CA,CAI5C,EAHA9F,CAGA,CAHIsB,CAAAS,MAGJ,CAFA6D,CAAA,CAAQI,CAAAC,OAAA,CAAW,CAAX,CAAcjG,CAAd,CAAR,CAEA,CADA6F,CAAA,CAAQC,CAAR,CAAaxE,CAAA,CAAM,CAAN,CAAAF,QAAA,CAAiBsE,CAAjB,CAAgC,EAAhC,CAAb,CACA,CAAAM,CAAA,CAAMA,CAAAtD,UAAA,CAAc1C,CAAd,CAAkBsB,CAAA,CAAM,CAAN,CAAArB,OAAlB,CAER2F,EAAA,CAAQI,CAAR,CACA,OAAOR,EAAA,CAAUrF,CAAAT,KAAA,CAAU,EAAV,CAAV,CAlBqB,CAL+C,CAAlC,CAA7C,CAzjBsC,CAArC,CAAA,CA0mBET,MA1mBF,CA0mBUA,MAAAC,QA1mBV;", +"sources":["angular-sanitize.js"], +"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","obj","items","split","i","length","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","lowercase","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","stack.last","specialElements","RegExp","all","text","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","parts","spaceRe","exec","spaceBefore","spaceAfter","content","hiddenPre","innerHTML","textContent","innerText","encodeEntities","NON_ALPHANUMERIC_REGEXP","charCodeAt","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"] +} \ No newline at end of file diff --git a/setup/pub/magento/setup/add-database.js b/setup/pub/magento/setup/add-database.js index 841d8e81ccdf9..e255483f4afc6 100644 --- a/setup/pub/magento/setup/add-database.js +++ b/setup/pub/magento/setup/add-database.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/app.js b/setup/pub/magento/setup/app.js index ec890084324a8..c74f4a1551a96 100644 --- a/setup/pub/magento/setup/app.js +++ b/setup/pub/magento/setup/app.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/auth-dialog.js b/setup/pub/magento/setup/auth-dialog.js index b2b905120a3f8..9e2fcf0537d86 100644 --- a/setup/pub/magento/setup/auth-dialog.js +++ b/setup/pub/magento/setup/auth-dialog.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/complete-backup.js b/setup/pub/magento/setup/complete-backup.js index d1d404853eb05..19062731a7a4c 100644 --- a/setup/pub/magento/setup/complete-backup.js +++ b/setup/pub/magento/setup/complete-backup.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/create-admin-account.js b/setup/pub/magento/setup/create-admin-account.js index dd8357dd9a568..905406110684e 100644 --- a/setup/pub/magento/setup/create-admin-account.js +++ b/setup/pub/magento/setup/create-admin-account.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/create-backup.js b/setup/pub/magento/setup/create-backup.js index 2ff55e4087d00..b4a56d42b8278 100644 --- a/setup/pub/magento/setup/create-backup.js +++ b/setup/pub/magento/setup/create-backup.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/customize-your-store.js b/setup/pub/magento/setup/customize-your-store.js index bcec183f34a0c..9242f59b3a7dc 100644 --- a/setup/pub/magento/setup/customize-your-store.js +++ b/setup/pub/magento/setup/customize-your-store.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/data-option.js b/setup/pub/magento/setup/data-option.js index b90d42e2dc840..ca003ba3f9321 100644 --- a/setup/pub/magento/setup/data-option.js +++ b/setup/pub/magento/setup/data-option.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -25,4 +25,4 @@ angular.module('data-option', ['ngStorage']) $scope.$watch('component.dataOption', function(value) { $localStorage.dataOption = value; }); - }]); \ No newline at end of file + }]); diff --git a/setup/pub/magento/setup/extension-grid.js b/setup/pub/magento/setup/extension-grid.js index e5fc525dbd1bc..e657a0955b3d3 100644 --- a/setup/pub/magento/setup/extension-grid.js +++ b/setup/pub/magento/setup/extension-grid.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/home.js b/setup/pub/magento/setup/home.js index 3c72130be860c..7959eb3bcf5d7 100644 --- a/setup/pub/magento/setup/home.js +++ b/setup/pub/magento/setup/home.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/install-extension-grid.js b/setup/pub/magento/setup/install-extension-grid.js index 0ec3b66911f10..964c4f9dd3f21 100644 --- a/setup/pub/magento/setup/install-extension-grid.js +++ b/setup/pub/magento/setup/install-extension-grid.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/install.js b/setup/pub/magento/setup/install.js index e1c7c0a125336..47c82736bb622 100644 --- a/setup/pub/magento/setup/install.js +++ b/setup/pub/magento/setup/install.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/landing.js b/setup/pub/magento/setup/landing.js index 31ef19adb6b40..5c508a65cdbcc 100644 --- a/setup/pub/magento/setup/landing.js +++ b/setup/pub/magento/setup/landing.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/main.js b/setup/pub/magento/setup/main.js index 3f359df3232d7..e307319088c26 100644 --- a/setup/pub/magento/setup/main.js +++ b/setup/pub/magento/setup/main.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/marketplace-credentials.js b/setup/pub/magento/setup/marketplace-credentials.js index ec7bb6d254873..f65bee361e9b3 100644 --- a/setup/pub/magento/setup/marketplace-credentials.js +++ b/setup/pub/magento/setup/marketplace-credentials.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/module-grid.js b/setup/pub/magento/setup/module-grid.js index 21dec8795f135..8c5b0c48ba670 100644 --- a/setup/pub/magento/setup/module-grid.js +++ b/setup/pub/magento/setup/module-grid.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/readiness-check.js b/setup/pub/magento/setup/readiness-check.js index 1b89ea2be06a5..ae84cd10fdbef 100644 --- a/setup/pub/magento/setup/readiness-check.js +++ b/setup/pub/magento/setup/readiness-check.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/remove-dialog.js b/setup/pub/magento/setup/remove-dialog.js index 96a63ec5193b2..6ce02ba511128 100644 --- a/setup/pub/magento/setup/remove-dialog.js +++ b/setup/pub/magento/setup/remove-dialog.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/select-version.js b/setup/pub/magento/setup/select-version.js index cc338f05489ca..dbfc315437ad5 100644 --- a/setup/pub/magento/setup/select-version.js +++ b/setup/pub/magento/setup/select-version.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -29,8 +29,15 @@ angular.module('select-version', ['ngStorage']) $http.get('index.php/select-version/systemPackage', {'responseType' : 'json'}) .success(function (data) { if (data.responseType != 'error') { - if (data.packages.length == 1) { - $scope.upgradeProcessError = true; + $scope.upgradeProcessError = true; + + angular.forEach(data.packages, function (value, key) { + if (!value.current) { + return $scope.upgradeProcessError = false; + } + }); + + if ($scope.upgradeProcessError) { $scope.upgradeProcessErrorMessage = "You're already using the latest version, there's nothing for us to do."; } else { $scope.selectedOption = []; @@ -49,8 +56,11 @@ angular.module('select-version', ['ngStorage']) $scope.currentVersion = value.name; } }); - $scope.selectedOption = $scope.versions[0].versionInfo; - $scope.upgradeReadyForNext = true; + + if ($scope.versions.length > 0) { + $scope.selectedOption = $scope.versions[0].versionInfo; + $scope.upgradeReadyForNext = true; + } } } else { @@ -170,9 +180,12 @@ angular.module('select-version', ['ngStorage']) }); } }); - $scope.selectedOption = $scope.versions[0].versionInfo; - $scope.upgradeReadyForNext = true; - } + + if ($scope.versions.length > 0) { + $scope.selectedOption = $scope.versions[0].versionInfo; + $scope.upgradeReadyForNext = true; + } + }; $scope.update = function() { var selectedVersionInfo = angular.fromJson($scope.selectedOption); diff --git a/setup/pub/magento/setup/start-updater.js b/setup/pub/magento/setup/start-updater.js index 5b90c5333cdd1..e1ed53bab3f70 100644 --- a/setup/pub/magento/setup/start-updater.js +++ b/setup/pub/magento/setup/start-updater.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/success.js b/setup/pub/magento/setup/success.js index ed23aa8c37133..df06d5f89470c 100644 --- a/setup/pub/magento/setup/success.js +++ b/setup/pub/magento/setup/success.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/system-config.js b/setup/pub/magento/setup/system-config.js index b8f6f16725802..bb2a2d0612c19 100644 --- a/setup/pub/magento/setup/system-config.js +++ b/setup/pub/magento/setup/system-config.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/update-extension-grid.js b/setup/pub/magento/setup/update-extension-grid.js index 8f7149bf1645e..4450444972e5d 100644 --- a/setup/pub/magento/setup/update-extension-grid.js +++ b/setup/pub/magento/setup/update-extension-grid.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/pub/magento/setup/updater-success.js b/setup/pub/magento/setup/updater-success.js index d2e98394251c8..0f44d1a04cee5 100644 --- a/setup/pub/magento/setup/updater-success.js +++ b/setup/pub/magento/setup/updater-success.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ @@ -8,8 +8,16 @@ angular.module('updater-success', ['ngStorage']) .controller('updaterSuccessController', ['$scope', '$state', '$localStorage', '$window', 'navigationService', function ($scope, $state, $localStorage, $window, navigationService) { if ($localStorage.successPageAction) { $scope.successPageAction = $localStorage.successPageAction; - $scope.successPageActionMessage = $scope.successPageAction + - ($scope.endsWith($scope.successPageAction, 'e') ? 'd' : 'ed'); + switch (true) { + case $scope.endsWith($scope.successPageAction, 'd'): + $scope.successPageActionMessage = $scope.successPageAction; + break; + case $scope.endsWith($scope.successPageAction, 'e'): + $scope.successPageActionMessage = $scope.successPageAction + 'd'; + break; + default: + $scope.successPageActionMessage = $scope.successPageAction + 'ed'; + } } if ($localStorage.packages) { $scope.packages = $localStorage.packages; diff --git a/setup/pub/magento/setup/web-configuration.js b/setup/pub/magento/setup/web-configuration.js index 164ce5ba63c41..63dec9ead2aab 100644 --- a/setup/pub/magento/setup/web-configuration.js +++ b/setup/pub/magento/setup/web-configuration.js @@ -1,11 +1,11 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ 'use strict'; angular.module('web-configuration', ['ngStorage']) - .controller('webConfigurationController', ['$scope', '$state', '$localStorage', function ($scope, $state, $localStorage) { + .controller('webConfigurationController', ['$scope', '$state', '$localStorage', '$http', function ($scope, $state, $localStorage, $http) { $scope.config = { address: { base_url: '', @@ -68,12 +68,12 @@ angular.module('web-configuration', ['ngStorage']) $scope.$watch('config.address.base_url', function() { if (angular.equals($scope.config.https.text, '') || angular.isUndefined($scope.config.https.text)) { - $scope.config.https.text = $scope.config.address.base_url.replace('http', 'https'); + $scope.config.https.text = $scope.config.address.base_url.replace('http://', 'https://'); } }); $scope.populateHttps = function() { - $scope.config.https.text = $scope.config.address.base_url.replace('http', 'https'); + $scope.config.https.text = $scope.config.address.base_url.replace('http://', 'https://'); }; $scope.showEncryptKey = function() { @@ -119,4 +119,28 @@ angular.module('web-configuration', ['ngStorage']) $scope.webconfig.submitted = false; } }); + + // Validate URL + $scope.validateUrl = function () { + if (!$scope.webconfig.submitted) { + $http.post('index.php/url-check', $scope.config) + .success(function (data) { + $scope.validateUrl.result = data; + if ($scope.validateUrl.result.successUrl && $scope.validateUrl.result.successSecureUrl) { + $scope.nextState(); + } + if (!$scope.validateUrl.result.successUrl) { + $scope.webconfig.submitted = true; + $scope.webconfig.base_url.$setValidity('url', false); + } + if (!$scope.validateUrl.result.successSecureUrl) { + $scope.webconfig.submitted = true; + $scope.webconfig.https.$setValidity('url', false); + } + }) + .error(function (data) { + $scope.validateUrl.failed = data; + }); + } + }; }]); diff --git a/setup/pub/styles/setup.css b/setup/pub/styles/setup.css index 61893c04c3f16..980e8233a0950 100644 --- a/setup/pub/styles/setup.css +++ b/setup/pub/styles/setup.css @@ -1,6 +1,6 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -.abs-action-delete,.abs-icon,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.validation-symbol:after{color:#e22626;content:'*';font-weight:400;margin-left:3px}.abs-modal-overlay,.modals-overlay{background:rgba(0,0,0,.35);bottom:0;left:0;position:fixed;right:0;top:0}.abs-action-delete>span,.abs-visually-hidden,.action-multicheck-wrap .action-multicheck-toggle>span,.admin__actions-switch-checkbox,.admin__control-fields .admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label)>.admin__field-label,.admin__field-tooltip .admin__field-tooltip-action span,.customize-your-store .customize-your-store-default .legend,.extensions-information .list .extension-delete>span,.form-el-checkbox,.form-el-radio,.selectmenu .action-delete>span,.selectmenu .action-edit>span,.selectmenu .action-save>span,.selectmenu-toggle span,.tooltip .help a span,.tooltip .help span span,[class*=admin__control-grouped]>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.abs-visually-hidden-reset,.admin__field-group-columns>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label[class]{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.abs-clearfix:after,.abs-clearfix:before,.action-multicheck-wrap:after,.action-multicheck-wrap:before,.actions-split:after,.actions-split:before,.admin__control-table-pagination:after,.admin__control-table-pagination:before,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:before,.admin__data-grid-filters-footer:after,.admin__data-grid-filters-footer:before,.admin__data-grid-filters:after,.admin__data-grid-filters:before,.admin__data-grid-header-row:after,.admin__data-grid-header-row:before,.admin__field-complex:after,.admin__field-complex:before,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .magento-message .insert-title-inner:before,.modal-slide .main-col .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:before,.page-actions._fixed:after,.page-actions._fixed:before,.page-content:after,.page-content:before,.page-header-actions:after,.page-header-actions:before,.page-main-actions:not(._hidden):after,.page-main-actions:not(._hidden):before{content:'';display:table}.abs-clearfix:after,.action-multicheck-wrap:after,.actions-split:after,.admin__control-table-pagination:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-filters-footer:after,.admin__data-grid-filters:after,.admin__data-grid-header-row:after,.admin__field-complex:after,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:after,.page-actions._fixed:after,.page-content:after,.page-header-actions:after,.page-main-actions:not(._hidden):after{clear:both}.abs-list-reset-styles{margin:0;padding:0;list-style:none}.abs-draggable-handle,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle,.admin__control-table .draggable-handle,.data-grid .data-grid-draggable-row-cell .draggable-handle{cursor:-webkit-grab;cursor:move;font-size:0;margin-top:-4px;padding:0 1rem 0 0;vertical-align:middle;display:inline-block;text-decoration:none}.abs-draggable-handle:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:before,.admin__control-table .draggable-handle:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:before{-webkit-font-smoothing:antialiased;font-size:1.8rem;line-height:inherit;color:#9e9e9e;content:'\e617';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.abs-draggable-handle:hover:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:hover:before,.admin__control-table .draggable-handle:hover:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:hover:before{color:#858585}.abs-config-scope-label,.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]:before{bottom:-1.3rem;color:gray;content:attr(data-config-scope);font-size:1.1rem;font-weight:400;min-width:15rem;position:absolute;right:0;text-transform:lowercase}.abs-word-wrap,.admin__field:not(.admin__field-option)>.admin__field-label{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;box-sizing:border-box}*,:after,:before{box-sizing:inherit}:focus{box-shadow:none;outline:0}._keyfocus :focus{box-shadow:0 0 0 1px #008bdb}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}embed,img,object,video{max-width:100%}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/light/opensans-300.eot);src:url(../fonts/opensans/light/opensans-300.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/light/opensans-300.woff2) format('woff2'),url(../fonts/opensans/light/opensans-300.woff) format('woff'),url(../fonts/opensans/light/opensans-300.ttf) format('truetype'),url('../fonts/opensans/light/opensans-300.svg#Open Sans') format('svg');font-weight:300;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/regular/opensans-400.eot);src:url(../fonts/opensans/regular/opensans-400.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/regular/opensans-400.woff2) format('woff2'),url(../fonts/opensans/regular/opensans-400.woff) format('woff'),url(../fonts/opensans/regular/opensans-400.ttf) format('truetype'),url('../fonts/opensans/regular/opensans-400.svg#Open Sans') format('svg');font-weight:400;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/semibold/opensans-600.eot);src:url(../fonts/opensans/semibold/opensans-600.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/semibold/opensans-600.woff2) format('woff2'),url(../fonts/opensans/semibold/opensans-600.woff) format('woff'),url(../fonts/opensans/semibold/opensans-600.ttf) format('truetype'),url('../fonts/opensans/semibold/opensans-600.svg#Open Sans') format('svg');font-weight:600;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/bold/opensans-700.eot);src:url(../fonts/opensans/bold/opensans-700.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/bold/opensans-700.woff2) format('woff2'),url(../fonts/opensans/bold/opensans-700.woff) format('woff'),url(../fonts/opensans/bold/opensans-700.ttf) format('truetype'),url('../fonts/opensans/bold/opensans-700.svg#Open Sans') format('svg');font-weight:700;font-style:normal}html{font-size:62.5%}body{color:#333;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.36;font-size:1.4rem}h1{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2.8rem}h2{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2rem}h3{margin:0 0 2rem;color:#41362f;font-weight:600;line-height:1.2;font-size:1.7rem}h4,h5,h6{font-weight:600;margin-top:0}p{margin:0 0 1em}small{font-size:1.2rem}a{color:#008bdb;text-decoration:none}a:hover{color:#0fa7ff;text-decoration:underline}dl,ol,ul{padding-left:0}nav ol,nav ul{list-style:none;margin:0;padding:0}html{height:100%}body{background-color:#fff;min-height:100%;min-width:102.4rem}.page-wrapper{background-color:#fff;display:inline-block;margin-left:-4px;vertical-align:top;width:calc(100% - 8.8rem)}.page-content{padding-bottom:3rem;padding-left:3rem;padding-right:3rem}.notices-wrapper{margin:0 3rem}.notices-wrapper .messages{margin-bottom:0}.row{margin-left:0;margin-right:0}.row:after{clear:both;content:'';display:table}.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9,.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{min-height:1px;padding-left:0;padding-right:0;position:relative}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}.row-gutter{margin-left:-1.5rem;margin-right:-1.5rem}.row-gutter>[class*=col-]{padding-left:1.5rem;padding-right:1.5rem}.abs-clearer:after,.extension-manager-content:after,.extension-manager-title:after,.form-row:after,.header:after,.nav:after,body:after{clear:both;content:'';display:table}.ng-cloak{display:none!important}.hide.hide{display:none}.show.show{display:block}.text-center{text-align:center}.text-right{text-align:right}@font-face{font-family:Icons;src:url(../fonts/icons/icons.eot);src:url(../fonts/icons/icons.eot?#iefix) format('embedded-opentype'),url(../fonts/icons/icons.woff2) format('woff2'),url(../fonts/icons/icons.woff) format('woff'),url(../fonts/icons/icons.ttf) format('truetype'),url(../fonts/icons/icons.svg#Icons) format('svg');font-weight:400;font-style:normal}[class*=icon-]{display:inline-block;line-height:1}.icon-failed:before,.icon-success:before,[class*=icon-]:after{font-family:Icons}.icon-success{color:#79a22e}.icon-success:before{content:'\e62d'}.icon-failed{color:#e22626}.icon-failed:before{content:'\e632'}.icon-success-thick:after{content:'\e62d'}.icon-collapse:after{content:'\e615'}.icon-failed-thick:after{content:'\e632'}.icon-expand:after{content:'\e616'}.icon-warning:after{content:'\e623'}.icon-failed-round,.icon-success-round{border-radius:100%;color:#fff;font-size:2.5rem;height:1em;position:relative;text-align:center;width:1em}.icon-failed-round:after,.icon-success-round:after{bottom:0;font-size:.5em;left:0;position:absolute;right:0;top:.45em}.icon-success-round{background-color:#79a22e}.icon-success-round:after{content:'\e62d'}.icon-failed-round{background-color:#e22626}.icon-failed-round:after{content:'\e632'}dl,ol,ul{margin-top:0}.list{padding-left:0}.list>li{display:block;margin-bottom:.75em;position:relative}.list>li>.icon-failed,.list>li>.icon-success{font-size:1.6em;left:-.1em;position:absolute;top:0}.list>li>.icon-success{color:#79a22e}.list>li>.icon-failed{color:#e22626}.list-item-failed,.list-item-icon,.list-item-success,.list-item-warning{padding-left:3.5rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{left:-.1em;position:absolute}.list-item-success:before{color:#79a22e}.list-item-failed:before{color:#e22626}.list-item-warning:before{color:#ef672f}.list-definition{margin:0 0 3rem;padding:0}.list-definition>dt{clear:left;float:left}.list-definition>dd{margin-bottom:1em;margin-left:20rem}.btn-wrap{margin:0 auto}.btn-wrap .btn{width:100%}.btn{background:#e3e3e3;border:none;color:#514943;display:inline-block;font-size:1.6rem;font-weight:600;padding:.45em .9em;text-align:center}.btn:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.btn:active{background-color:#d6d6d6}.btn.disabled,.btn[disabled]{cursor:default;opacity:.5;pointer-events:none}.ie9 .btn.disabled,.ie9 .btn[disabled]{background-color:#f0f0f0;opacity:1;text-shadow:none}.btn-large{padding:.75em 1.25em}.btn-medium{font-size:1.4rem;padding:.5em 1.5em .6em}.btn-link{background-color:transparent;border:none;color:#008bdb;font-family:1.6rem;font-size:1.5rem}.btn-link:active,.btn-link:focus,.btn-link:hover{background-color:transparent;color:#0fa7ff}.btn-prime{background-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.btn-prime:focus,.btn-prime:hover{background-color:#f65405;background-repeat:repeat-x;background-image:linear-gradient(to right,#e04f00 0,#f65405 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e04f00', endColorstr='#f65405', GradientType=1);color:#fff}.btn-prime:active{background-color:#e04f00;background-repeat:repeat-x;background-image:linear-gradient(to right,#f65405 0,#e04f00 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f65405', endColorstr='#e04f00', GradientType=1);color:#fff}.ie9 .btn-prime.disabled,.ie9 .btn-prime[disabled]{background-color:#fd6e23}.ie9 .btn-prime.disabled:active,.ie9 .btn-prime.disabled:hover,.ie9 .btn-prime[disabled]:active,.ie9 .btn-prime[disabled]:hover{background-color:#fd6e23;-webkit-filter:none;filter:none}.btn-secondary{background-color:#514943;color:#fff}.btn-secondary:hover{background-color:#5f564f;color:#fff}.btn-secondary:active,.btn-secondary:focus{background-color:#574e48;color:#fff}.ie9 .btn-secondary.disabled,.ie9 .btn-secondary[disabled]{background-color:#514943}.ie9 .btn-secondary.disabled:active,.ie9 .btn-secondary[disabled]:active{background-color:#514943;-webkit-filter:none;filter:none}[class*=btn-wrap-triangle]{overflow:hidden;position:relative}[class*=btn-wrap-triangle] .btn:after{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.btn-wrap-triangle-right{display:inline-block;padding-right:1.74rem;position:relative}.btn-wrap-triangle-right .btn{text-indent:.92rem}.btn-wrap-triangle-right .btn:after{border-color:transparent transparent transparent #e3e3e3;border-width:1.84rem 0 1.84rem 1.84rem;left:100%;margin-left:-1.74rem}.btn-wrap-triangle-right .btn:focus:after,.btn-wrap-triangle-right .btn:hover:after{border-left-color:#dbdbdb}.btn-wrap-triangle-right .btn:active:after{border-left-color:#d6d6d6}.btn-wrap-triangle-right .btn:not(.disabled):active,.btn-wrap-triangle-right .btn:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn.disabled:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:after{border-color:transparent transparent transparent #f0f0f0}.ie9 .btn-wrap-triangle-right .btn.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn.disabled:focus:after,.ie9 .btn-wrap-triangle-right .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:focus:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:hover:after{border-left-color:#f0f0f0}.btn-wrap-triangle-right .btn-prime:after{border-color:transparent transparent transparent #eb5202}.btn-wrap-triangle-right .btn-prime:focus:after,.btn-wrap-triangle-right .btn-prime:hover:after{border-left-color:#f65405}.btn-wrap-triangle-right .btn-prime:active:after{border-left-color:#e04f00}.btn-wrap-triangle-right .btn-prime:not(.disabled):active,.btn-wrap-triangle-right .btn-prime:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:after{border-color:transparent transparent transparent #fd6e23}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:hover:after{border-left-color:#fd6e23}.btn-wrap-triangle-left{display:inline-block;padding-left:1.74rem}.btn-wrap-triangle-left .btn{text-indent:-.92rem}.btn-wrap-triangle-left .btn:after{border-color:transparent #e3e3e3 transparent transparent;border-width:1.84rem 1.84rem 1.84rem 0;margin-right:-1.74rem;right:100%}.btn-wrap-triangle-left .btn:focus:after,.btn-wrap-triangle-left .btn:hover:after{border-right-color:#dbdbdb}.btn-wrap-triangle-left .btn:active:after{border-right-color:#d6d6d6}.btn-wrap-triangle-left .btn:not(.disabled):active,.btn-wrap-triangle-left .btn:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn.disabled:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:after{border-color:transparent #f0f0f0 transparent transparent}.ie9 .btn-wrap-triangle-left .btn.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:hover:after{border-right-color:#f0f0f0}.btn-wrap-triangle-left .btn-prime:after{border-color:transparent #eb5202 transparent transparent}.btn-wrap-triangle-left .btn-prime:focus:after,.btn-wrap-triangle-left .btn-prime:hover:after{border-right-color:#e04f00}.btn-wrap-triangle-left .btn-prime:active:after{border-right-color:#f65405}.btn-wrap-triangle-left .btn-prime:not(.disabled):active,.btn-wrap-triangle-left .btn-prime:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:after{border-color:transparent #fd6e23 transparent transparent}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:hover:after{border-right-color:#fd6e23}.btn-expand{background-color:transparent;border:none;color:#303030;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700;padding:0;position:relative}.btn-expand.expanded:after{border-color:transparent transparent #303030;border-width:0 .285em .36em}.btn-expand.expanded:hover:after{border-color:transparent transparent #3d3d3d}.btn-expand:hover{background-color:transparent;border:none;color:#3d3d3d}.btn-expand:hover:after{border-color:#3d3d3d transparent transparent}.btn-expand:after{border-color:#303030 transparent transparent;border-style:solid;border-width:.36em .285em 0;content:'';height:0;left:100%;margin-left:.5em;margin-top:-.18em;position:absolute;top:50%;width:0}[class*=col-] .form-el-input,[class*=col-] .form-el-select{width:100%}.form-fieldset{border:none;margin:0 0 1em;padding:0}.form-row{margin-bottom:2.2rem}.form-row .form-row{margin-bottom:.4rem}.form-row .form-label{display:block;font-weight:600;padding:.6rem 2.1em 0 0;text-align:right}.form-row .form-label.required{position:relative}.form-row .form-label.required:after{color:#eb5202;content:'*';font-size:1.15em;position:absolute;right:.7em;top:.5em}.form-row .form-el-checkbox+.form-label:before,.form-row .form-el-radio+.form-label:before{top:.7rem}.form-row .form-el-checkbox+.form-label:after,.form-row .form-el-radio+.form-label:after{top:1.1rem}.form-row.form-row-text{padding-top:.6rem}.form-row.form-row-text .action-sign-out{font-size:1.2rem;margin-left:1rem}.form-note{font-size:1.2rem;font-weight:600;margin-top:1rem}.form-el-dummy{display:none}.fieldset{border:0;margin:0;min-width:0;padding:0}input:not([disabled]):focus,textarea:not([disabled]):focus{box-shadow:none}.form-el-input{border:1px solid #adadad;color:#303030;padding:.35em .55em .5em}.form-el-input:hover{border-color:#949494}.form-el-input:focus{border-color:#008bdb}.form-el-input:required{box-shadow:none}.form-label{margin-bottom:.5em}[class*=form-label][for]{cursor:pointer}.form-el-insider-wrap{display:table;width:100%}.form-el-insider-input{display:table-cell;width:100%}.form-el-insider{border-radius:2px;display:table-cell;padding:.43em .55em .5em 0;vertical-align:top}.form-legend,.form-legend-expand,.form-legend-light{display:block;margin:0}.form-legend,.form-legend-expand{font-size:1.25em;font-weight:600;margin-bottom:2.5em;padding-top:1.5em}.form-legend{border-top:1px solid #ccc;width:100%}.form-legend-light{font-size:1em;margin-bottom:1.5em}.form-legend-expand{cursor:pointer;transition:opacity .2s linear}.form-legend-expand:hover{opacity:.85}.form-legend-expand.expanded:after{content:'\e615'}.form-legend-expand:after{content:'\e616';font-family:Icons;font-size:1.15em;font-weight:400;margin-left:.5em;vertical-align:sub}.form-el-checkbox.disabled+.form-label,.form-el-checkbox.disabled+.form-label:before,.form-el-checkbox[disabled]+.form-label,.form-el-checkbox[disabled]+.form-label:before,.form-el-radio.disabled+.form-label,.form-el-radio.disabled+.form-label:before,.form-el-radio[disabled]+.form-label,.form-el-radio[disabled]+.form-label:before{cursor:default;opacity:.5;pointer-events:none}.form-el-checkbox:not(.disabled)+.form-label:hover:before,.form-el-checkbox:not([disabled])+.form-label:hover:before,.form-el-radio:not(.disabled)+.form-label:hover:before,.form-el-radio:not([disabled])+.form-label:hover:before{border-color:#514943}.form-el-checkbox+.form-label,.form-el-radio+.form-label{font-weight:400;padding-left:2em;padding-right:0;position:relative;text-align:left;transition:border-color .1s linear}.form-el-checkbox+.form-label:before,.form-el-radio+.form-label:before{border:1px solid;content:'';left:0;position:absolute;top:.1rem;transition:border-color .1s linear}.form-el-checkbox+.form-label:before{background-color:#fff;border-color:#adadad;border-radius:2px;font-size:1.2rem;height:1.6rem;line-height:1.2;width:1.6rem}.form-el-checkbox:checked+.form-label::before{content:'\e62d';font-family:Icons}.form-el-radio+.form-label:before{background-color:#fff;border:1px solid #adadad;border-radius:100%;height:1.8rem;width:1.8rem}.form-el-radio+.form-label:after{background:0 0;border:.5rem solid transparent;border-radius:100%;content:'';height:0;left:.4rem;position:absolute;top:.5rem;transition:background .3s linear;width:0}.form-el-radio:checked+.form-label{cursor:default}.form-el-radio:checked+.form-label:after{border-color:#514943}.form-select-label{border:1px solid #adadad;color:#303030;cursor:pointer;display:block;overflow:hidden;position:relative;z-index:0}.form-select-label:hover,.form-select-label:hover:after{border-color:#949494}.form-select-label:active,.form-select-label:active:after,.form-select-label:focus,.form-select-label:focus:after{border-color:#008bdb}.form-select-label:after{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:2.36em;z-index:-2}.ie9 .form-select-label:after{display:none}.form-select-label:before{border-color:#303030 transparent transparent;border-style:solid;border-width:5px 4px 0;content:'';height:0;margin-right:-4px;margin-top:-2.5px;position:absolute;right:1.18em;top:50%;width:0;z-index:-1}.ie9 .form-select-label:before{display:none}.form-select-label .form-el-select{background:0 0;border:none;border-radius:0;content:'';display:block;margin:0;padding:.35em calc(2.36em + 10%) .5em .55em;width:110%}.ie9 .form-select-label .form-el-select{padding-right:.55em;width:100%}.form-select-label .form-el-select::-ms-expand{display:none}.form-el-select{background:#fff;border:1px solid #adadad;border-radius:2px;color:#303030;display:block;padding:.35em .55em}.multiselect-custom{border:1px solid #adadad;height:45.2rem;margin:0 0 1.5rem;overflow:auto;position:relative}.multiselect-custom ul{margin:0;padding:0;list-style:none;min-width:29rem}.multiselect-custom .item{padding:1rem 1.4rem}.multiselect-custom .selected{background-color:#e0f6fe}.multiselect-custom .form-label{margin-bottom:0}[class*=form-el-].invalid{border-color:#e22626}[class*=form-el-].invalid+.error-container{display:block}.error-container{background-color:#fffbbb;border:1px solid #ee7d7d;color:#514943;display:none;font-size:1.19rem;margin-top:.2rem;padding:.8rem 1rem .9rem}.check-result-message{margin-left:.5em;min-height:3.68rem;-ms-align-items:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.check-result-text{margin-left:.5em}body:not([class]){min-width:0}.container{display:block;margin:0 auto 4rem;max-width:100rem;padding:0}.abs-action-delete,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.text-stretch{margin-bottom:1.5em}.page-title-jumbo{font-size:4rem;font-weight:300;letter-spacing:-.05em;margin-bottom:2.9rem}.page-title-jumbo-success:before{color:#79a22e;content:'\e62d';font-size:3.9rem;margin-left:-.3rem;margin-right:2.4rem}.list{margin-bottom:3rem}.list-dot .list-item{display:list-item;list-style-position:inside;margin-bottom:1.2rem}.list-title{color:#333;font-size:1.4rem;font-weight:700;letter-spacing:.025em;margin-bottom:1.2rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{font-family:Icons;font-size:1.6rem;top:0}.list-item-success:before{content:'\e62d';font-size:1.6rem}.list-item-failed:before{content:'\e632';font-size:1.4rem;left:.1rem;top:.2rem}.list-item-warning:before{content:'\e623';font-size:1.3rem;left:.2rem}.form-wrap{margin-bottom:3.6rem;padding-top:2.1rem}.form-el-label-horizontal{display:inline-block;font-size:1.3rem;font-weight:600;letter-spacing:.025em;margin-bottom:.4rem;margin-left:.4rem}.app-updater{min-width:768px}body._has-modal{height:100%;overflow:hidden;width:100%}.modals-overlay{z-index:899}.modal-popup,.modal-slide{bottom:0;min-width:0;position:fixed;right:0;top:0;visibility:hidden}.modal-popup._show,.modal-slide._show{visibility:visible}.modal-popup._show .modal-inner-wrap,.modal-slide._show .modal-inner-wrap{-ms-transform:translate(0,0);transform:translate(0,0)}.modal-popup .modal-inner-wrap,.modal-slide .modal-inner-wrap{background-color:#fff;box-shadow:0 0 12px 2px rgba(0,0,0,.35);opacity:1;pointer-events:auto}.modal-slide{left:14.8rem;z-index:900}.modal-slide._show .modal-inner-wrap{-ms-transform:translateX(0);transform:translateX(0)}.modal-slide .modal-inner-wrap{height:100%;overflow-y:auto;position:static;-ms-transform:translateX(100%);transform:translateX(100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;width:auto}.modal-slide._inner-scroll .modal-inner-wrap{overflow-y:visible;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.modal-slide._inner-scroll .modal-footer,.modal-slide._inner-scroll .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-slide._inner-scroll .modal-content{overflow-y:auto}.modal-slide._inner-scroll .modal-footer{margin-top:auto}.modal-slide .modal-content,.modal-slide .modal-footer,.modal-slide .modal-header{padding:0 2.6rem 2.6rem}.modal-slide .modal-header{padding-bottom:2.1rem;padding-top:2.1rem}.modal-popup{z-index:900;left:0;overflow-y:auto}.modal-popup._show .modal-inner-wrap{-ms-transform:translateY(0);transform:translateY(0)}.modal-popup .modal-inner-wrap{margin:5rem auto;width:75%;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;box-sizing:border-box;height:auto;left:0;position:absolute;right:0;-ms-transform:translateY(-200%);transform:translateY(-200%);transition-duration:.2s;transition-property:transform,visibility;transition-timing-function:ease}.modal-popup._inner-scroll{overflow-y:visible}.ie10 .modal-popup._inner-scroll,.ie9 .modal-popup._inner-scroll{overflow-y:auto}.modal-popup._inner-scroll .modal-inner-wrap{max-height:90%}.ie10 .modal-popup._inner-scroll .modal-inner-wrap,.ie9 .modal-popup._inner-scroll .modal-inner-wrap{max-height:none}.modal-popup._inner-scroll .modal-content{overflow-y:auto}.modal-popup .modal-content,.modal-popup .modal-footer,.modal-popup .modal-header{padding-left:3rem;padding-right:3rem}.modal-popup .modal-footer,.modal-popup .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-popup .modal-header{padding-bottom:1.2rem;padding-top:3rem}.modal-popup .modal-footer{margin-top:auto;padding-bottom:3rem}.modal-popup .modal-footer-actions{text-align:right}.admin__action-dropdown-wrap{display:inline-block;position:relative}.admin__action-dropdown-wrap .admin__action-dropdown-text:after{left:-6px;right:0}.admin__action-dropdown-wrap .admin__action-dropdown-menu{left:auto;right:0}.admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__action-dropdown-wrap.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin__action-dropdown-wrap._active .admin__action-dropdown-text:after,.admin__action-dropdown-wrap.active .admin__action-dropdown-text:after{background-color:#fff;content:'';height:6px;position:absolute;top:100%}.admin__action-dropdown-wrap._active .admin__action-dropdown-menu,.admin__action-dropdown-wrap.active .admin__action-dropdown-menu{display:block}.admin__action-dropdown-wrap._disabled .admin__action-dropdown{cursor:default}.admin__action-dropdown-wrap._disabled:hover .admin__action-dropdown{color:#333}.admin__action-dropdown{background-color:#fff;border:1px solid transparent;border-bottom:none;border-radius:0;box-shadow:none;color:#333;display:inline-block;font-size:1.3rem;font-weight:400;letter-spacing:-.025em;padding:.7rem 3.3rem .8rem 1.5rem;position:relative;vertical-align:baseline;z-index:2}.admin__action-dropdown._active:after,.admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .admin__action-dropdown:after,.active .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin__action-dropdown:focus,.admin__action-dropdown:hover{background-color:#fff;color:#000;text-decoration:none}.admin__action-dropdown:after{right:1.5rem}.admin__action-dropdown:before{margin-right:1rem}.admin__action-dropdown-menu{background-color:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;line-height:1.36;margin-top:-1px;min-width:120%;padding:.5rem 1rem;position:absolute;top:100%;transition:all .15s ease;z-index:1}.admin__action-dropdown-menu>li{display:block}.admin__action-dropdown-menu>li>a{color:#333;display:block;text-decoration:none;padding:.6rem .5rem}.selectmenu{display:inline-block;position:relative;text-align:left;z-index:1}.selectmenu._active{border-color:#007bdb;z-index:500}.selectmenu .action-delete,.selectmenu .action-edit,.selectmenu .action-save{background-color:transparent;border-color:transparent;box-shadow:none;padding:0 1rem}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover,.selectmenu .action-save:hover{background-color:transparent;border-color:transparent;box-shadow:none}.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before{content:'\e630'}.selectmenu .action-delete,.selectmenu .action-edit{border:0 solid #fff;border-left-width:1px;bottom:0;position:absolute;right:0;top:0;z-index:1}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover{border:0 solid #fff;border-left-width:1px}.selectmenu .action-save:before{content:'\e625'}.selectmenu .action-edit:before{content:'\e631'}.selectmenu-value{display:inline-block}.selectmenu-value input[type=text]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;border:0;display:inline;margin:0;width:6rem}body._keyfocus .selectmenu-value input[type=text]:focus{box-shadow:none}.selectmenu-toggle{padding-right:3rem;background:0 0;border-width:0;bottom:0;float:right;position:absolute;right:0;top:0;width:0}.selectmenu-toggle._active:after,.selectmenu-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.1rem;top:50%;transition:all .2s linear;width:0}._active .selectmenu-toggle:after,.active .selectmenu-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:hover:after{border-color:#000 transparent transparent}.selectmenu-toggle:active,.selectmenu-toggle:focus,.selectmenu-toggle:hover{background:0 0}.selectmenu._active .selectmenu-toggle:before{border-color:#007bdb}body._keyfocus .selectmenu-toggle:focus{box-shadow:none}.selectmenu-toggle:before{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';display:block;position:absolute;right:0;top:0;width:3.2rem}.selectmenu-items{background:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;float:left;left:-1px;margin-top:3px;max-width:20rem;min-width:calc(100% + 2px);position:absolute;top:100%}.selectmenu-items._active{display:block}.selectmenu-items ul{float:left;list-style-type:none;margin:0;min-width:100%;padding:0}.selectmenu-items li{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row;transition:background .2s linear}.selectmenu-items li:hover{background:#e3e3e3}.selectmenu-items li:last-child .selectmenu-item-action,.selectmenu-items li:last-child .selectmenu-item-action:visited{color:#008bdb;text-decoration:none}.selectmenu-items li:last-child .selectmenu-item-action:hover{color:#0fa7ff;text-decoration:underline}.selectmenu-items li:last-child .selectmenu-item-action:active{color:#ff5501;text-decoration:underline}.selectmenu-item{position:relative;width:100%;z-index:1}li._edit>.selectmenu-item{display:none}.selectmenu-item-edit{display:none;padding:.3rem 4rem .3rem .4rem;position:relative;white-space:nowrap;z-index:1}li:last-child .selectmenu-item-edit{padding-right:.4rem}.selectmenu-item-edit .admin__control-text{margin:0;width:5.4rem}li._edit .selectmenu-item-edit{display:block}.selectmenu-item-action{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background:0 0;border:0;color:#333;display:block;font-size:1.4rem;font-weight:400;min-width:100%;padding:1rem 6rem 1rem 1.5rem;text-align:left;transition:background .2s linear;width:5rem}.selectmenu-item-action:focus,.selectmenu-item-action:hover{background:#e3e3e3}.abs-actions-split-xl .action-default,.page-actions .actions-split .action-default{margin-right:4rem}.abs-actions-split-xl .action-toggle,.page-actions .actions-split .action-toggle{padding-right:4rem}.abs-actions-split-xl .action-toggle:after,.page-actions .actions-split .action-toggle:after{border-width:.9rem .6rem 0;margin-top:-.3rem;right:1.4rem}.actions-split{position:relative;z-index:400}.actions-split._active,.actions-split.active,.actions-split:hover{box-shadow:0 0 0 1px #007bdb}.actions-split._active .action-toggle.action-primary,.actions-split._active .action-toggle.primary,.actions-split.active .action-toggle.action-primary,.actions-split.active .action-toggle.primary{background-color:#ba4000;border-color:#ba4000}.actions-split._active .dropdown-menu,.actions-split.active .dropdown-menu{opacity:1;visibility:visible;display:block}.actions-split .action-default,.actions-split .action-toggle{float:left;margin:0}.actions-split .action-default._active,.actions-split .action-default.active,.actions-split .action-default:hover,.actions-split .action-toggle._active,.actions-split .action-toggle.active,.actions-split .action-toggle:hover{box-shadow:none}.actions-split .action-default{margin-right:3.2rem;min-width:9.3rem}.actions-split .action-toggle{padding-right:3.2rem;border-left-color:rgba(0,0,0,.2);bottom:0;padding-left:0;position:absolute;right:0;top:0}.actions-split .action-toggle._active:after,.actions-split .action-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .actions-split .action-toggle:after,.active .actions-split .action-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:hover:after{border-color:#000 transparent transparent}.actions-split .action-toggle.action-primary:after,.actions-split .action-toggle.action-secondary:after,.actions-split .action-toggle.primary:after,.actions-split .action-toggle.secondary:after{border-color:#fff transparent transparent}.actions-split .action-toggle>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-select-wrap{display:inline-block;position:relative}.action-select-wrap .action-select{padding-right:3.2rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:#fff;font-weight:400;text-align:left}.action-select-wrap .action-select._active:after,.action-select-wrap .action-select.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .action-select-wrap .action-select:after,.active .action-select-wrap .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:hover:after{border-color:#000 transparent transparent}.action-select-wrap .action-select:hover,.action-select-wrap .action-select:hover:before{border-color:#878787}.action-select-wrap .action-select:before{background-color:#e3e3e3;border:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:3.2rem}.action-select-wrap .action-select._active{border-color:#007bdb}.action-select-wrap .action-select._active:before{border-color:#007bdb #007bdb #007bdb #adadad}.action-select-wrap .action-select[disabled]{color:#333}.action-select-wrap .action-select[disabled]:after{border-color:#333 transparent transparent}.action-select-wrap._active{z-index:500}.action-select-wrap._active .action-select,.action-select-wrap._active .action-select:before{border-color:#007bdb}.action-select-wrap._active .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .abs-action-menu .action-submenu,.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu,.action-select-wrap .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:45rem;overflow-y:auto}.action-select-wrap .abs-action-menu .action-submenu ._disabled:hover,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .action-menu ._disabled:hover,.action-select-wrap .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled:hover{background:#fff}.action-select-wrap .abs-action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .action-menu ._disabled .action-menu-item,.action-select-wrap .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled .action-menu-item{cursor:default;opacity:.5}.action-select-wrap .action-menu-items{left:0;position:absolute;right:0;top:100%}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu{min-width:100%;position:static}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{position:absolute}.action-multicheck-wrap{display:inline-block;height:1.6rem;padding-top:1px;position:relative;width:3.1rem;z-index:200}.action-multicheck-wrap:hover .action-multicheck-toggle,.action-multicheck-wrap:hover .admin__control-checkbox+label:before{border-color:#878787}.action-multicheck-wrap._active .action-multicheck-toggle,.action-multicheck-wrap._active .admin__control-checkbox+label:before{border-color:#007bdb}.action-multicheck-wrap._active .abs-action-menu .action-submenu,.action-multicheck-wrap._active .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .action-menu,.action-multicheck-wrap._active .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu .action-submenu{opacity:1;visibility:visible;display:block}.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{background-color:#fff}.action-multicheck-wrap._disabled .action-multicheck-toggle,.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{border-color:#adadad;opacity:1}.action-multicheck-wrap .action-multicheck-toggle,.action-multicheck-wrap .admin__control-checkbox,.action-multicheck-wrap .admin__control-checkbox+label{float:left}.action-multicheck-wrap .action-multicheck-toggle{border-radius:0 1px 1px 0;height:1.6rem;margin-left:-1px;padding:0;position:relative;transition:border-color .1s linear;width:1.6rem}.action-multicheck-wrap .action-multicheck-toggle._active:after,.action-multicheck-wrap .action-multicheck-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .action-multicheck-wrap .action-multicheck-toggle:after,.active .action-multicheck-wrap .action-multicheck-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:hover:after{border-color:#000 transparent transparent}.action-multicheck-wrap .action-multicheck-toggle:focus{border-color:#007bdb}.action-multicheck-wrap .action-multicheck-toggle:after{right:.3rem}.action-multicheck-wrap .abs-action-menu .action-submenu,.action-multicheck-wrap .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap .action-menu,.action-multicheck-wrap .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:-1.1rem;margin-top:1px;right:auto;text-align:left}.action-multicheck-wrap .action-menu-item{white-space:nowrap}.admin__action-multiselect-wrap{display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.admin__action-multiselect-wrap.action-select-wrap:focus{box-shadow:none}.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .action-menu,.admin__action-multiselect-wrap.action-select-wrap .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:none;overflow-y:inherit}.admin__action-multiselect-wrap .action-menu-item{transition:background-color .1s linear}.admin__action-multiselect-wrap .action-menu-item._selected{background-color:#e0f6fe}.admin__action-multiselect-wrap .action-menu-item._hover{background-color:#e3e3e3}.admin__action-multiselect-wrap .action-menu-item._unclickable{cursor:default}.admin__action-multiselect-wrap .admin__action-multiselect{border:1px solid #adadad;cursor:pointer;display:block;min-height:3.2rem;padding-right:3.6rem;white-space:normal}.admin__action-multiselect-wrap .admin__action-multiselect:after{bottom:1.25rem;top:auto}.admin__action-multiselect-wrap .admin__action-multiselect:before{height:3.3rem;top:auto}.admin__control-table-wrapper .admin__action-multiselect-wrap{position:static}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect{position:relative}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect:before{right:-1px;top:-1px}.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:34rem;right:auto;top:auto;z-index:1}.admin__action-multiselect-wrap .admin__action-multiselect-item-path{color:#a79d95;font-size:1.2rem;font-weight:400;padding-left:1rem}.admin__action-multiselect-actions-wrap{border-top:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;text-align:center}.admin__action-multiselect-actions-wrap .action-default{font-size:1.3rem;min-width:13rem}.admin__action-multiselect-text{padding:.6rem 1rem}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{text-align:left}.admin__action-multiselect-label{cursor:pointer;position:relative;z-index:1}.admin__action-multiselect-label:before{margin-right:.5rem}._unclickable .admin__action-multiselect-label{cursor:default;font-weight:700}.admin__action-multiselect-search-wrap{border-bottom:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;position:relative}.admin__action-multiselect-search{padding-right:3rem;width:100%}.admin__action-multiselect-search-label{display:block;font-size:1.5rem;height:1em;overflow:hidden;position:absolute;right:2.2rem;top:1.7rem;width:1em}.admin__action-multiselect-search-label:before{content:'\e60c'}.admin__action-multiselect-search-count{color:#a79d95;margin-top:1rem}.admin__action-multiselect-menu-inner{margin-bottom:0;max-height:46rem;overflow-y:auto}.admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{list-style:none;max-height:none;overflow:hidden;padding-left:2.2rem}.admin__action-multiselect-menu-inner ._hidden{display:none}.admin__action-multiselect-crumb{background-color:#f5f5f5;border:1px solid #a79d95;border-radius:1px;display:inline-block;font-size:1.2rem;margin:.3rem -4px .3rem .3rem;padding:.3rem 2.4rem .4rem 1rem;position:relative;transition:border-color .1s linear}.admin__action-multiselect-crumb:hover{border-color:#908379}.admin__action-multiselect-crumb .action-close{bottom:0;font-size:.5em;position:absolute;right:0;top:0;width:2rem}.admin__action-multiselect-crumb .action-close:hover{color:#000}.admin__action-multiselect-crumb .action-close:active,.admin__action-multiselect-crumb .action-close:focus{background-color:transparent}.admin__action-multiselect-crumb .action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__action-multiselect-tree .abs-action-menu .action-submenu,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .action-menu,.admin__action-multiselect-tree .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu{min-width:34.7rem}.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item{margin-top:.1rem}.admin__action-multiselect-tree .action-menu-item{margin-left:4.2rem;position:relative}.admin__action-multiselect-tree .action-menu-item._expended:before{border-left:1px dashed #a79d95;bottom:0;content:'';left:-1rem;position:absolute;top:1rem;width:1px}.admin__action-multiselect-tree .action-menu-item._expended .admin__action-multiselect-dropdown:before{content:'\e615'}.admin__action-multiselect-tree .action-menu-item._with-checkbox .admin__action-multiselect-label{padding-left:2.6rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{padding-left:3.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner:before{left:4.3rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:last-child:before{height:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after,.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{content:'';left:0;position:absolute}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after{border-top:1px dashed #a79d95;height:1px;top:2.1rem;width:5.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{border-left:1px dashed #a79d95;height:100%;top:0;width:1px}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._parent:after{width:4.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root{margin-left:-1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:after{left:3.2rem;width:2.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:before{left:3.2rem;top:1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root._parent:after{display:none}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:first-child:before{top:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:last-child:before{height:1rem}.admin__action-multiselect-tree .admin__action-multiselect-label{line-height:2.2rem;vertical-align:middle;word-break:break-all}.admin__action-multiselect-tree .admin__action-multiselect-label:before{left:0;position:absolute;top:.4rem}.admin__action-multiselect-dropdown{border-radius:50%;height:2.2rem;left:-2.2rem;position:absolute;top:1rem;width:2.2rem;z-index:1}.admin__action-multiselect-dropdown:before{background:#fff;color:#a79d95;content:'\e616';font-size:2.2rem}.admin__actions-switch{display:inline-block;position:relative;vertical-align:middle}.admin__field-control .admin__actions-switch{line-height:3.2rem}.admin__actions-switch+.admin__field-service{min-width:34rem}._disabled .admin__actions-switch-checkbox+.admin__actions-switch-label,.admin__actions-switch-checkbox.disabled+.admin__actions-switch-label{cursor:not-allowed;opacity:.5;pointer-events:none}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:before{left:15px}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:after{background:#79a22e}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label .admin__actions-switch-text:before{content:attr(data-text-on)}.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:after,.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:before{border-color:#007bdb}._error .admin__actions-switch-checkbox+.admin__actions-switch-label:after,._error .admin__actions-switch-checkbox+.admin__actions-switch-label:before{border-color:#e22626}.admin__actions-switch-label{cursor:pointer;display:inline-block;height:22px;line-height:22px;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.admin__actions-switch-label:after,.admin__actions-switch-label:before{left:0;position:absolute;right:auto;top:0}.admin__actions-switch-label:before{background:#fff;border:1px solid #aaa6a0;border-radius:100%;content:'';display:block;height:22px;transition:left .2s ease-in 0s;width:22px;z-index:1}.admin__actions-switch-label:after{background:#e3e3e3;border:1px solid #aaa6a0;border-radius:12px;content:'';display:block;height:22px;transition:background .2s ease-in 0s;vertical-align:middle;width:37px;z-index:0}.admin__actions-switch-text:before{content:attr(data-text-off);padding-left:47px;white-space:nowrap}.abs-action-delete,.abs-action-reset,.action-close,.admin__field-fallback-reset,.extensions-information .list .extension-delete,.notifications-close,.search-global-field._active .search-global-action{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0}.abs-action-delete:hover,.abs-action-reset:hover,.action-close:hover,.admin__field-fallback-reset:hover,.extensions-information .list .extension-delete:hover,.notifications-close:hover,.search-global-field._active .search-global-action:hover{background-color:transparent;border:none;box-shadow:none}.abs-action-default,.abs-action-pattern,.abs-action-primary,.abs-action-quaternary,.abs-action-secondary,.abs-action-tertiary,.action-default,.action-primary,.action-quaternary,.action-secondary,.action-tertiary,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions>button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary,button,button.primary,button.secondary,button.tertiary{border:1px solid;border-radius:0;display:inline-block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:1.36;padding:.6rem 1em;text-align:center;vertical-align:baseline}.abs-action-default.disabled,.abs-action-default[disabled],.abs-action-pattern.disabled,.abs-action-pattern[disabled],.abs-action-primary.disabled,.abs-action-primary[disabled],.abs-action-quaternary.disabled,.abs-action-quaternary[disabled],.abs-action-secondary.disabled,.abs-action-secondary[disabled],.abs-action-tertiary.disabled,.abs-action-tertiary[disabled],.action-default.disabled,.action-default[disabled],.action-primary.disabled,.action-primary[disabled],.action-quaternary.disabled,.action-quaternary[disabled],.action-secondary.disabled,.action-secondary[disabled],.action-tertiary.disabled,.action-tertiary[disabled],.modal-popup .modal-footer .action-primary.disabled,.modal-popup .modal-footer .action-primary[disabled],.modal-popup .modal-footer .action-secondary.disabled,.modal-popup .modal-footer .action-secondary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.action-secondary.disabled,.page-actions .page-actions-buttons>button.action-secondary[disabled],.page-actions .page-actions-buttons>button.disabled,.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions .page-actions-buttons>button[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.action-secondary.disabled,.page-actions>button.action-secondary[disabled],.page-actions>button.disabled,.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],.page-actions>button[disabled],button.disabled,button.primary.disabled,button.primary[disabled],button.secondary.disabled,button.secondary[disabled],button.tertiary.disabled,button.tertiary[disabled],button[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-l,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary{font-size:1.6rem;letter-spacing:.025em;padding-bottom:.6875em;padding-top:.6875em}.abs-action-delete,.extensions-information .list .extension-delete{display:inline-block;font-size:1.6rem;margin-left:1.2rem;padding-top:.7rem;text-decoration:none;vertical-align:middle}.abs-action-delete:after,.extensions-information .list .extension-delete:after{color:#666;content:'\e630'}.abs-action-delete:hover:after,.extensions-information .list .extension-delete:hover:after{color:#35302c}.abs-action-button-as-link,.action-advanced,.data-grid .action-delete{line-height:1.36;padding:0;color:#008bdb;text-decoration:none;background:0 0;border:0;display:inline;font-weight:400;border-radius:0}.abs-action-button-as-link:visited,.action-advanced:visited,.data-grid .action-delete:visited{color:#008bdb;text-decoration:none}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{text-decoration:underline}.abs-action-button-as-link:active,.action-advanced:active,.data-grid .action-delete:active{color:#ff5501;text-decoration:underline}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{color:#0fa7ff}.abs-action-button-as-link:active,.abs-action-button-as-link:focus,.abs-action-button-as-link:hover,.action-advanced:active,.action-advanced:focus,.action-advanced:hover,.data-grid .action-delete:active,.data-grid .action-delete:focus,.data-grid .action-delete:hover{background:0 0;border:0}.abs-action-button-as-link.disabled,.abs-action-button-as-link[disabled],.action-advanced.disabled,.action-advanced[disabled],.data-grid .action-delete.disabled,.data-grid .action-delete[disabled],fieldset[disabled] .abs-action-button-as-link,fieldset[disabled] .action-advanced,fieldset[disabled] .data-grid .action-delete{color:#008bdb;opacity:.5;cursor:default;pointer-events:none;text-decoration:underline}.abs-action-button-as-link:active,.abs-action-button-as-link:not(:focus),.action-advanced:active,.action-advanced:not(:focus),.data-grid .action-delete:active,.data-grid .action-delete:not(:focus){box-shadow:none}.abs-action-button-as-link:focus,.action-advanced:focus,.data-grid .action-delete:focus{color:#0fa7ff}.abs-action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.abs-action-default:active,.abs-action-default:focus,.abs-action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.abs-action-primary,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary,button.primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.abs-action-primary:active,.abs-action-primary:focus,.abs-action-primary:hover,.page-actions .page-actions-buttons>button.action-primary:active,.page-actions .page-actions-buttons>button.action-primary:focus,.page-actions .page-actions-buttons>button.action-primary:hover,.page-actions .page-actions-buttons>button.primary:active,.page-actions .page-actions-buttons>button.primary:focus,.page-actions .page-actions-buttons>button.primary:hover,.page-actions>button.action-primary:active,.page-actions>button.action-primary:focus,.page-actions>button.action-primary:hover,.page-actions>button.primary:active,.page-actions>button.primary:focus,.page-actions>button.primary:hover,button.primary:active,button.primary:focus,button.primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-primary.disabled,.abs-action-primary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],button.primary.disabled,button.primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-secondary,.modal-popup .modal-footer .action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions>button.action-secondary,button.secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.abs-action-secondary:active,.abs-action-secondary:focus,.abs-action-secondary:hover,.modal-popup .modal-footer .action-primary:active,.modal-popup .modal-footer .action-primary:focus,.modal-popup .modal-footer .action-primary:hover,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions .page-actions-buttons>button.action-secondary:focus,.page-actions .page-actions-buttons>button.action-secondary:hover,.page-actions>button.action-secondary:active,.page-actions>button.action-secondary:focus,.page-actions>button.action-secondary:hover,button.secondary:active,button.secondary:focus,button.secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-secondary:active,.modal-popup .modal-footer .action-primary:active,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions>button.action-secondary:active,button.secondary:active{background-color:#35302c}.abs-action-tertiary,.modal-popup .modal-footer .action-secondary,button.tertiary{background-color:transparent;border-color:transparent;text-shadow:none;color:#008bdb}.abs-action-tertiary:active,.abs-action-tertiary:focus,.abs-action-tertiary:hover,.modal-popup .modal-footer .action-secondary:active,.modal-popup .modal-footer .action-secondary:focus,.modal-popup .modal-footer .action-secondary:hover,button.tertiary:active,button.tertiary:focus,button.tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#0fa7ff;text-decoration:underline}.abs-action-quaternary,.page-actions .page-actions-buttons>button,.page-actions>button{background-color:transparent;border-color:transparent;text-shadow:none;color:#333}.abs-action-quaternary:active,.abs-action-quaternary:focus,.abs-action-quaternary:hover,.page-actions .page-actions-buttons>button:active,.page-actions .page-actions-buttons>button:focus,.page-actions .page-actions-buttons>button:hover,.page-actions>button:active,.page-actions>button:focus,.page-actions>button:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#1a1a1a}.abs-action-menu,.actions-split .abs-action-menu .action-submenu,.actions-split .abs-action-menu .action-submenu .action-submenu,.actions-split .action-menu,.actions-split .action-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.actions-split .dropdown-menu{text-align:left;background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu._active,.actions-split .abs-action-menu .action-submenu .action-submenu._active,.actions-split .abs-action-menu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .action-menu._active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .actions-split .dropdown-menu .action-submenu._active,.actions-split .dropdown-menu._active{display:block}.abs-action-menu>li,.actions-split .abs-action-menu .action-submenu .action-submenu>li,.actions-split .abs-action-menu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .action-menu>li,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .actions-split .dropdown-menu .action-submenu>li,.actions-split .dropdown-menu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu>li>a:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .abs-action-menu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .action-menu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu>li>a:hover{text-decoration:none}.abs-action-menu>li._visible,.abs-action-menu>li:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu .action-submenu>li:hover,.actions-split .abs-action-menu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .action-menu>li._visible,.actions-split .action-menu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu>li:hover,.actions-split .dropdown-menu>li._visible,.actions-split .dropdown-menu>li:hover{background-color:#e3e3e3}.abs-action-menu>li:active,.actions-split .abs-action-menu .action-submenu .action-submenu>li:active,.actions-split .abs-action-menu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .action-menu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu>li:active,.actions-split .dropdown-menu>li:active{background-color:#cacaca}.abs-action-menu>li._parent,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent,.actions-split .abs-action-menu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .action-menu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent,.actions-split .dropdown-menu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-menu-item,.abs-action-menu .item,.actions-split .abs-action-menu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .item,.actions-split .abs-action-menu .action-submenu .item,.actions-split .action-menu .action-menu-item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .item,.actions-split .action-menu .item,.actions-split .actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .actions-split .dropdown-menu .action-submenu .item,.actions-split .dropdown-menu .action-menu-item,.actions-split .dropdown-menu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu a.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .abs-action-menu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .action-menu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu a.action-menu-item{color:#333}.abs-action-menu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.abs-action-wrap-triangle{position:relative}.abs-action-wrap-triangle .action-default{width:100%}.abs-action-wrap-triangle .action-default:after,.abs-action-wrap-triangle .action-default:before{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.abs-action-wrap-triangle .action-default:active,.abs-action-wrap-triangle .action-default:focus,.abs-action-wrap-triangle .action-default:hover{box-shadow:none}._keyfocus .abs-action-wrap-triangle .action-default:focus{box-shadow:0 0 0 1px #007bdb}.ie10 .abs-action-wrap-triangle .action-default.disabled,.ie10 .abs-action-wrap-triangle .action-default[disabled],.ie9 .abs-action-wrap-triangle .action-default.disabled,.ie9 .abs-action-wrap-triangle .action-default[disabled]{background-color:#fcfcfc;opacity:1;text-shadow:none}.abs-action-wrap-triangle-right{display:inline-block;padding-right:1.6rem;position:relative}.abs-action-wrap-triangle-right .action-default:after,.abs-action-wrap-triangle-right .action-default:before{border-color:transparent transparent transparent #e3e3e3;border-width:1.7rem 0 1.6rem 1.7rem;left:100%;margin-left:-1.7rem}.abs-action-wrap-triangle-right .action-default:before{border-left-color:#949494;right:-1px}.abs-action-wrap-triangle-right .action-default:active:after,.abs-action-wrap-triangle-right .action-default:focus:after,.abs-action-wrap-triangle-right .action-default:hover:after{border-left-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-right .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-right .action-default[disabled]:after{border-color:transparent transparent transparent #fcfcfc}.abs-action-wrap-triangle-right .action-primary:after{border-color:transparent transparent transparent #eb5202}.abs-action-wrap-triangle-right .action-primary:active:after,.abs-action-wrap-triangle-right .action-primary:focus:after,.abs-action-wrap-triangle-right .action-primary:hover:after{border-left-color:#ba4000}.abs-action-wrap-triangle-left{display:inline-block;padding-left:1.6rem}.abs-action-wrap-triangle-left .action-default{text-indent:-.85rem}.abs-action-wrap-triangle-left .action-default:after,.abs-action-wrap-triangle-left .action-default:before{border-color:transparent #e3e3e3 transparent transparent;border-width:1.7rem 1.7rem 1.6rem 0;margin-right:-1.7rem;right:100%}.abs-action-wrap-triangle-left .action-default:before{border-right-color:#949494;left:-1px}.abs-action-wrap-triangle-left .action-default:active:after,.abs-action-wrap-triangle-left .action-default:focus:after,.abs-action-wrap-triangle-left .action-default:hover:after{border-right-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-left .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-left .action-default[disabled]:after{border-color:transparent #fcfcfc transparent transparent}.abs-action-wrap-triangle-left .action-primary:after{border-color:transparent #eb5202 transparent transparent}.abs-action-wrap-triangle-left .action-primary:active:after,.abs-action-wrap-triangle-left .action-primary:focus:after,.abs-action-wrap-triangle-left .action-primary:hover:after{border-right-color:#ba4000}.action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.action-default:active,.action-default:focus,.action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.action-primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.action-primary:active,.action-primary:focus,.action-primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-primary.disabled,.action-primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.action-secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.action-secondary:active,.action-secondary:focus,.action-secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-secondary:active{background-color:#35302c}.action-quaternary,.action-tertiary{background-color:transparent;border-color:transparent;text-shadow:none}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover,.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none}.action-tertiary{color:#008bdb}.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{color:#0fa7ff;text-decoration:underline}.action-quaternary{color:#333}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover{color:#1a1a1a}.action-close>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.action-close:before{content:'\e62f';transition:color .1s linear}.action-close:hover{cursor:pointer;text-decoration:none}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu .action-submenu .action-submenu._active,.abs-action-menu .action-submenu._active,.action-menu .action-submenu._active,.action-menu._active,.actions-split .action-menu .action-submenu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .dropdown-menu .action-submenu._active{display:block}.abs-action-menu .action-submenu .action-submenu>li,.abs-action-menu .action-submenu>li,.action-menu .action-submenu>li,.action-menu>li,.actions-split .action-menu .action-submenu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .dropdown-menu .action-submenu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu .action-submenu .action-submenu>li>a:hover,.abs-action-menu .action-submenu>li>a:hover,.action-menu .action-submenu>li>a:hover,.action-menu>li>a:hover,.actions-split .action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu>li>a:hover{text-decoration:none}.abs-action-menu .action-submenu .action-submenu>li._visible,.abs-action-menu .action-submenu .action-submenu>li:hover,.abs-action-menu .action-submenu>li._visible,.abs-action-menu .action-submenu>li:hover,.action-menu .action-submenu>li._visible,.action-menu .action-submenu>li:hover,.action-menu>li._visible,.action-menu>li:hover,.actions-split .action-menu .action-submenu .action-submenu>li._visible,.actions-split .action-menu .action-submenu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu>li:hover{background-color:#e3e3e3}.abs-action-menu .action-submenu .action-submenu>li:active,.abs-action-menu .action-submenu>li:active,.action-menu .action-submenu>li:active,.action-menu>li:active,.actions-split .action-menu .action-submenu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu>li:active{background-color:#cacaca}.abs-action-menu .action-submenu .action-submenu>li._parent,.abs-action-menu .action-submenu>li._parent,.action-menu .action-submenu>li._parent,.action-menu>li._parent,.actions-split .action-menu .action-submenu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.abs-action-menu .action-submenu>li._parent>.action-menu-item,.action-menu .action-submenu>li._parent>.action-menu-item,.action-menu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .item,.abs-action-menu .action-submenu .item,.action-menu .action-menu-item,.action-menu .action-submenu .action-menu-item,.action-menu .action-submenu .item,.action-menu .item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .item,.actions-split .action-menu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu .action-submenu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu .action-submenu,.ie9 .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .action-menu .action-submenu,.ie9 .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu .action-submenu .action-submenu a.action-menu-item,.abs-action-menu .action-submenu a.action-menu-item,.action-menu .action-submenu a.action-menu-item,.action-menu a.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu a.action-menu-item{color:#333}.abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.abs-action-menu .action-submenu a.action-menu-item:focus,.action-menu .action-submenu a.action-menu-item:focus,.action-menu a.action-menu-item:focus,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.messages .message:last-child{margin:0 0 2rem}.message{background:#fffbbb;border:none;border-radius:0;color:#333;font-size:1.4rem;margin:0 0 1px;padding:1.8rem 4rem 1.8rem 5.5rem;position:relative;text-shadow:none}.message:before{background:0 0;border:0;color:#007bdb;content:'\e61a';font-family:Icons;font-size:1.9rem;font-style:normal;font-weight:400;height:auto;left:1.9rem;line-height:inherit;margin-top:-1.3rem;position:absolute;speak:none;text-shadow:none;top:50%;width:auto}.message-notice:before{color:#007bdb;content:'\e61a'}.message-warning:before{color:#eb5202;content:'\e623'}.message-error{background:#fcc}.message-error:before{color:#e22626;content:'\e632';font-size:1.5rem;left:2.2rem;margin-top:-1rem}.message-success:before{color:#79a22e;content:'\e62d'}.message-spinner:before{display:none}.message-spinner .spinner{font-size:2.5rem;left:1.5rem;position:absolute;top:1.5rem}.message-in-rating-edit{margin-left:1.8rem;margin-right:1.8rem}.modal-popup .action-close,.modal-slide .action-close{color:#736963;position:absolute;right:0;top:0;z-index:1}.modal-popup .action-close:active,.modal-slide .action-close:active{-ms-transform:none;transform:none}.modal-popup .action-close:active:before,.modal-slide .action-close:active:before{font-size:1.8rem}.modal-popup .action-close:hover:before,.modal-slide .action-close:hover:before{color:#58504b}.modal-popup .action-close:before,.modal-slide .action-close:before{font-size:2rem}.modal-popup .action-close:focus,.modal-slide .action-close:focus{background-color:transparent}.modal-popup.prompt .prompt-message{padding:2rem 0}.modal-popup.prompt .prompt-message input{width:100%}.modal-popup.confirm .modal-inner-wrap .message,.modal-popup.prompt .modal-inner-wrap .message{background:#fff}.modal-popup.modal-system-messages .modal-inner-wrap{background:#fffbbb}.modal-popup._image-box .modal-inner-wrap{margin:5rem auto;max-width:78rem;position:static}.modal-popup._image-box .thumbnail-preview{padding-bottom:3rem;text-align:center}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image-block{border:1px solid #ccc;margin:0 auto 2rem;max-width:58rem;padding:2rem}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image{max-height:54rem}.modal-popup .modal-title{font-size:2.4rem;margin-right:6.4rem}.modal-popup .modal-footer{padding-top:2.6rem;text-align:right}.modal-popup .action-close{padding:3rem}.modal-popup .action-close:active,.modal-popup .action-close:focus{background:0 0;padding-right:3.1rem;padding-top:3.1rem}.modal-slide .modal-content-new-attribute{-webkit-overflow-scrolling:touch;overflow:auto;padding-bottom:0}.modal-slide .modal-content-new-attribute iframe{margin-bottom:-2.5rem}.modal-slide .modal-title{font-size:2.1rem;margin-right:5.7rem}.modal-slide .action-close{padding:2.1rem 2.6rem}.modal-slide .action-close:active{padding-right:2.7rem;padding-top:2.2rem}.modal-slide .page-main-actions{margin-bottom:.6rem;margin-top:2.1rem}.modal-slide .magento-message{padding:0 3rem 3rem;position:relative}.modal-slide .magento-message .insert-title-inner,.modal-slide .main-col .insert-title-inner{border-bottom:1px solid #adadad;margin:0 0 2rem;padding-bottom:.5rem}.modal-slide .magento-message .insert-actions,.modal-slide .main-col .insert-actions{float:right}.modal-slide .magento-message .title,.modal-slide .main-col .title{font-size:1.6rem;padding-top:.5rem}.modal-slide .main-col,.modal-slide .side-col{float:left;padding-bottom:0}.modal-slide .main-col:after,.modal-slide .side-col:after{display:none}.modal-slide .side-col{width:20%}.modal-slide .main-col{padding-right:0;width:80%}.modal-slide .content-footer .form-buttons{float:right}.modal-title{font-weight:400;margin-bottom:0;min-height:1em}.modal-title span{font-size:1.4rem;font-style:italic;margin-left:1rem}.spinner{display:inline-block;font-size:4rem;height:1em;margin-right:1.5rem;position:relative;width:1em}.spinner>span:nth-child(1){animation-delay:.27s;-ms-transform:rotate(-315deg);transform:rotate(-315deg)}.spinner>span:nth-child(2){animation-delay:.36s;-ms-transform:rotate(-270deg);transform:rotate(-270deg)}.spinner>span:nth-child(3){animation-delay:.45s;-ms-transform:rotate(-225deg);transform:rotate(-225deg)}.spinner>span:nth-child(4){animation-delay:.54s;-ms-transform:rotate(-180deg);transform:rotate(-180deg)}.spinner>span:nth-child(5){animation-delay:.63s;-ms-transform:rotate(-135deg);transform:rotate(-135deg)}.spinner>span:nth-child(6){animation-delay:.72s;-ms-transform:rotate(-90deg);transform:rotate(-90deg)}.spinner>span:nth-child(7){animation-delay:.81s;-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.spinner>span:nth-child(8){animation-delay:.9;-ms-transform:rotate(0deg);transform:rotate(0deg)}@keyframes fade{0%{background-color:#514943}100%{background-color:#fff}}.spinner>span{-ms-transform:scale(0.4);transform:scale(0.4);animation-name:fade;animation-duration:.72s;animation-iteration-count:infinite;animation-direction:linear;background-color:#fff;border-radius:6px;clip:rect(0 .28571429em .1em 0);height:.1em;margin-top:.5em;position:absolute;width:1em}.ie9 .spinner{background:url(../images/ajax-loader.gif) center no-repeat}.ie9 .spinner>span{display:none}.popup-loading{background:rgba(255,255,255,.8);border-color:#ef672f;color:#ef672f;font-size:14px;font-weight:700;left:50%;margin-left:-100px;padding:100px 0 10px;position:fixed;text-align:center;top:40%;width:200px;z-index:1003}.popup-loading:after{background-image:url(../images/loader-1.gif);content:'';height:64px;left:50%;margin:-32px 0 0 -32px;position:absolute;top:40%;width:64px;z-index:2}.loading-mask,.loading-old{background:rgba(255,255,255,.4);bottom:0;left:0;position:fixed;right:0;top:0;z-index:2003}.loading-mask img,.loading-old img{display:none}.loading-mask p,.loading-old p{margin-top:118px}.loading-mask .loader,.loading-old .loader{background:url(../images/loader-1.gif) 50% 30% no-repeat #f7f3eb;border-radius:5px;bottom:0;color:#575757;font-size:14px;font-weight:700;height:160px;left:0;margin:auto;opacity:.95;position:absolute;right:0;text-align:center;top:0;width:160px}.admin-user{float:right;line-height:1.36;margin-left:.3rem;z-index:490}.admin-user._active .admin__action-dropdown,.admin-user.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin-user .admin__action-dropdown{height:3.3rem;padding:.7rem 2.8rem .4rem 4rem}.admin-user .admin__action-dropdown._active:after,.admin-user .admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:after{border-color:#777 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.3rem;top:50%;transition:all .2s linear;width:0}._active .admin-user .admin__action-dropdown:after,.active .admin-user .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin-user .admin__action-dropdown:before{color:#777;content:'\e600';font-size:2rem;left:1.1rem;margin-top:-1.1rem;position:absolute;top:50%}.admin-user .admin__action-dropdown:hover:before{color:#333}.admin-user .admin__action-dropdown-menu{min-width:20rem;padding-left:1rem;padding-right:1rem}.admin-user .admin__action-dropdown-menu>li>a{padding-left:.5em;padding-right:1.8rem;transition:background-color .1s linear;white-space:nowrap}.admin-user .admin__action-dropdown-menu>li>a:hover{background-color:#e0f6fe;color:#333}.admin-user .admin__action-dropdown-menu>li>a:active{background-color:#c7effd;bottom:-1px;position:relative}.admin-user .admin__action-dropdown-menu .admin-user-name{text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:20rem;overflow:hidden;vertical-align:top}.admin-user-account-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:11.2rem}.search-global{float:right;margin-right:-.3rem;position:relative;z-index:480}.search-global-field{min-width:5rem}.search-global-field._active .search-global-input{background-color:#fff;border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);padding-right:4rem;width:25rem}.search-global-field._active .search-global-action{display:block;height:3.3rem;position:absolute;right:0;text-indent:-100%;top:0;width:5rem;z-index:3}.search-global-field .autocomplete-results{height:3.3rem;position:absolute;right:0;top:0;width:25rem}.search-global-field .search-global-menu{border:1px solid #007bdb;border-top-color:transparent;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin-top:-2px;padding:0;position:absolute;right:0;top:100%;z-index:2}.search-global-field .search-global-menu:after{background-color:#fff;content:'';height:5px;left:0;position:absolute;right:0;top:-5px}.search-global-field .search-global-menu>li{background-color:#fff;border-top:1px solid #ddd;display:block;font-size:1.2rem;padding:.75rem 1.4rem .55rem}.search-global-field .search-global-menu>li._active{background-color:#e0f6fe}.search-global-field .search-global-menu .title{display:block;font-size:1.4rem}.search-global-field .search-global-menu .type{color:#1a1a1a;display:block}.search-global-label{cursor:pointer;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;z-index:2}.search-global-label:active{-ms-transform:scale(0.9);transform:scale(0.9)}.search-global-label:hover:before{color:#000}.search-global-label:before{color:#777;content:'\e60c';font-size:2rem}.search-global-input{background-color:transparent;border:1px solid transparent;font-size:1.4rem;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;transition:all .1s linear,width .3s linear;width:5rem;z-index:1}.search-global-action{display:none}.notifications-wrapper{float:right;line-height:1;position:relative}.notifications-wrapper.active{z-index:500}.notifications-wrapper.active .notifications-action{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.notifications-wrapper.active .notifications-action:after{background-color:#fff;border:none;content:'';display:block;height:6px;left:-6px;margin-top:0;position:absolute;right:0;top:100%;width:auto}.notifications-wrapper .admin__action-dropdown-menu{padding:1rem 0 0;width:32rem}.notifications-action{color:#777;height:3.3rem;padding:.75rem 2rem .65rem}.notifications-action:after{display:none}.notifications-action:before{content:'\e607';font-size:1.9rem;margin-right:0}.notifications-action:active:before{position:relative;top:1px}.notifications-action .notifications-counter{background-color:#e22626;border-radius:1em;color:#fff;display:inline-block;font-size:1.1rem;font-weight:700;left:50%;margin-left:.3em;margin-top:-1.1em;padding:.3em .5em;position:absolute;top:50%}.notifications-entry{line-height:1.36;padding:.6rem 2rem .8rem;position:relative;transition:background-color .1s linear}.notifications-entry:hover{background-color:#e0f6fe}.notifications-entry.notifications-entry-last{margin:0 2rem;padding:.3rem 0 1.3rem;text-align:center}.notifications-entry.notifications-entry-last:hover{background-color:transparent}.notifications-entry+.notifications-entry-last{border-top:1px solid #ddd;padding-bottom:.6rem}.notifications-entry ._cutted{cursor:pointer}.notifications-entry ._cutted .notifications-entry-description-start:after{content:'...'}.notifications-entry-title{color:#ef672f;display:block;font-size:1.1rem;font-weight:700;margin-bottom:.7rem;margin-right:1em}.notifications-entry-description{color:#333;font-size:1.1rem;margin-bottom:.8rem}.notifications-entry-description-end{display:none}.notifications-entry-description-end._show{display:inline}.notifications-entry-time{color:#777;font-size:1.1rem}.notifications-close{line-height:1;padding:1rem;position:absolute;right:0;top:.6rem}.notifications-close:before{color:#ccc;content:'\e620';transition:color .1s linear}.notifications-close:hover:before{color:#b3b3b3}.notifications-close:active{-ms-transform:scale(0.95);transform:scale(0.95)}.page-header-actions{padding-top:1.1rem}.page-header-hgroup{padding-right:1.5rem}.page-title{color:#333;font-size:2.8rem}.page-header{padding:1.5rem 3rem}.menu-wrapper{display:inline-block;position:relative;width:8.8rem;z-index:700}.menu-wrapper:before{background-color:#373330;bottom:0;content:'';left:0;position:fixed;top:0;width:8.8rem;z-index:699}.menu-wrapper._fixed{left:0;position:fixed;top:0}.menu-wrapper._fixed~.page-wrapper{margin-left:8.8rem}.menu-wrapper .logo{display:block;height:8.8rem;padding:2.4rem 0 2.2rem;position:relative;text-align:center;z-index:700}._keyfocus .menu-wrapper .logo:focus{background-color:#4a4542;box-shadow:none}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a{background-color:#373330}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a:after{display:none}.menu-wrapper .logo:hover .logo-img{-webkit-filter:brightness(1.1);filter:brightness(1.1)}.menu-wrapper .logo:active .logo-img{-ms-transform:scale(0.95);transform:scale(0.95)}.menu-wrapper .logo .logo-img{height:4.2rem;transition:-webkit-filter .2s linear,filter .2s linear,transform .1s linear;width:3.5rem}.abs-menu-separator,.admin__menu .item-partners>a:after,.admin__menu .level-0:first-child>a:after{background-color:#736963;content:'';display:block;height:1px;left:0;margin-left:16%;position:absolute;top:0;width:68%}.admin__menu li{display:block}.admin__menu .level-0:first-child>a{position:relative}.admin__menu .level-0._active>a,.admin__menu .level-0:hover>a{color:#f7f3eb}.admin__menu .level-0._active>a{background-color:#524d49}.admin__menu .level-0:hover>a{background-color:#4a4542}.admin__menu .level-0>a{color:#aaa6a0;display:block;font-size:1rem;letter-spacing:.025em;min-height:6.2rem;padding:1.2rem .5rem .5rem;position:relative;text-align:center;text-decoration:none;text-transform:uppercase;transition:background-color .1s linear;word-wrap:break-word;z-index:700}.admin__menu .level-0>a:focus{box-shadow:none}.admin__menu .level-0>a:before{content:'\e63a';display:block;font-size:2.2rem;height:2.2rem}.admin__menu .level-0>.submenu{background-color:#4a4542;box-shadow:0 0 3px #000;left:100%;min-height:calc(8.8rem + 2rem + 100%);padding:2rem 0 0;position:absolute;top:0;-ms-transform:translateX(-100%);transform:translateX(-100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;visibility:hidden;z-index:697}.ie10 .admin__menu .level-0>.submenu,.ie11 .admin__menu .level-0>.submenu{height:100%}.admin__menu .level-0._show>.submenu{-ms-transform:translateX(0);transform:translateX(0);visibility:visible;z-index:698}.admin__menu .level-1{margin-left:1.5rem;margin-right:1.5rem}.admin__menu [class*=level-]:not(.level-0) a{display:block;padding:1.25rem 1.5rem}.admin__menu [class*=level-]:not(.level-0) a:hover{background-color:#403934}.admin__menu [class*=level-]:not(.level-0) a:active{background-color:#322c29;padding-bottom:1.15rem;padding-top:1.35rem}.admin__menu .submenu li{min-width:23.8rem}.admin__menu .submenu a{color:#fcfcfc;transition:background-color .1s linear}.admin__menu .submenu a:focus,.admin__menu .submenu a:hover{box-shadow:none;text-decoration:none}._keyfocus .admin__menu .submenu a:focus{background-color:#403934}._keyfocus .admin__menu .submenu a:active{background-color:#322c29}.admin__menu .submenu .parent{margin-bottom:4.5rem}.admin__menu .submenu .parent .submenu-group-title{color:#a79d95;display:block;font-size:1.6rem;font-weight:600;margin-bottom:.7rem;padding:1.25rem 1.5rem;pointer-events:none}.admin__menu .submenu .column{display:table-cell}.admin__menu .submenu-title{color:#fff;display:block;font-size:2.2rem;font-weight:600;margin-bottom:4.2rem;margin-left:3rem;margin-right:5.8rem}.admin__menu .submenu-sub-title{color:#fff;display:block;font-size:1.2rem;margin:-3.8rem 5.8rem 3.8rem 3rem}.admin__menu .action-close{padding:2.4rem 2.8rem;position:absolute;right:0;top:0}.admin__menu .action-close:before{color:#a79d95;font-size:1.7rem}.admin__menu .action-close:hover:before{color:#fff}.admin__menu .item-dashboard>a:before{content:'\e604';font-size:1.8rem;padding-top:.4rem}.admin__menu .item-sales>a:before{content:'\e60b'}.admin__menu .item-catalog>a:before{content:'\e608'}.admin__menu .item-customer>a:before{content:'\e603';font-size:2.6rem;position:relative;top:-.4rem}.admin__menu .item-marketing>a:before{content:'\e609';font-size:2rem;padding-top:.2rem}.admin__menu .item-content>a:before{content:'\e602';font-size:2.4rem;position:relative;top:-.2rem}.admin__menu .item-report>a:before{content:'\e60a'}.admin__menu .item-stores>a:before{content:'\e60d';font-size:1.9rem;padding-top:.3rem}.admin__menu .item-system>a:before{content:'\e610'}.admin__menu .item-partners._active>a:after,.admin__menu .item-system._current+.item-partners>a:after{display:none}.admin__menu .item-partners>a{padding-bottom:1rem}.admin__menu .item-partners>a:before{content:'\e612'}.admin__menu .level-0>.submenu>ul>.level-1:only-of-type>.submenu-group-title,.admin__menu .submenu .column:only-of-type .submenu-group-title{display:none}.admin__menu-overlay{bottom:0;left:0;position:fixed;right:0;top:0;z-index:697}.store-switcher{color:#333;float:left;font-size:1.3rem;margin-top:.7rem}.store-switcher .admin__action-dropdown{background-color:#f8f8f8;margin-left:.5em}.store-switcher .dropdown{display:inline-block;position:relative}.store-switcher .dropdown:after,.store-switcher .dropdown:before{content:'';display:table}.store-switcher .dropdown:after{clear:both}.store-switcher .dropdown .action.toggle{cursor:pointer;display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e607';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle:active:after,.store-switcher .dropdown .action.toggle:hover:after{color:#333}.store-switcher .dropdown .action.toggle.active{display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle.active:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e618';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle.active:active:after,.store-switcher .dropdown .action.toggle.active:hover:after{color:#333}.store-switcher .dropdown .dropdown-menu{margin:4px 0 0;padding:0;list-style:none;background:#fff;border:1px solid #aaa6a0;min-width:19.5rem;z-index:100;box-sizing:border-box;display:none;position:absolute;top:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.store-switcher .dropdown .dropdown-menu li{margin:0;padding:0}.store-switcher .dropdown .dropdown-menu li:hover{background:0 0;cursor:pointer}.store-switcher .dropdown.active{overflow:visible}.store-switcher .dropdown.active .dropdown-menu{display:block}.store-switcher .dropdown-menu{left:0;margin-top:.5em;max-height:250px;overflow-y:auto;padding-top:.25em}.store-switcher .dropdown-menu li{border:0;cursor:default}.store-switcher .dropdown-menu li:hover{cursor:default}.store-switcher .dropdown-menu li a,.store-switcher .dropdown-menu li span{color:#333;display:block;padding:.5rem 1.3rem}.store-switcher .dropdown-menu li a{text-decoration:none}.store-switcher .dropdown-menu li a:hover{background:#e9e9e9}.store-switcher .dropdown-menu li span{color:#adadad;cursor:default}.store-switcher .dropdown-menu li.current span{background:#eee;color:#333}.store-switcher .dropdown-menu .store-switcher-store a,.store-switcher .dropdown-menu .store-switcher-store span{padding-left:2.6rem}.store-switcher .dropdown-menu .store-switcher-store-view a,.store-switcher .dropdown-menu .store-switcher-store-view span{padding-left:3.9rem}.store-switcher .dropdown-menu .dropdown-toolbar{border-top:1px solid #ebebeb;margin-top:1rem}.store-switcher .dropdown-menu .dropdown-toolbar a:before{content:'\e610';margin-right:.25em;position:relative;top:1px}.store-switcher-label{font-weight:700}.store-switcher-alt{display:inline-block;position:relative}.store-switcher-alt.active .dropdown-menu{display:block}.store-switcher-alt .dropdown-menu{margin-top:2px;white-space:nowrap}.store-switcher-alt .dropdown-menu ul{list-style:none;margin:0;padding:0}.store-switcher-alt strong{color:#a79d95;display:block;font-size:14px;font-weight:500;line-height:1.333;padding:5px 10px}.store-switcher-alt .store-selected{color:#676056;cursor:pointer;font-size:12px;font-weight:400;line-height:1.333}.store-switcher-alt .store-selected:after{-webkit-font-smoothing:antialiased;color:#afadac;content:'\e02c';font-style:normal;font-weight:400;margin:0 0 0 3px;speak:none;vertical-align:text-top}.store-switcher-alt .store-switcher-store,.store-switcher-alt .store-switcher-website{padding:0}.store-switcher-alt .store-switcher-store:hover,.store-switcher-alt .store-switcher-website:hover{background:0 0}.store-switcher-alt .manage-stores,.store-switcher-alt .store-switcher-all,.store-switcher-alt .store-switcher-store-view{padding:0}.store-switcher-alt .manage-stores>a,.store-switcher-alt .store-switcher-all>a{color:#676056;display:block;font-size:12px;padding:8px 15px;text-decoration:none}.store-switcher-website{margin:5px 0 0}.store-switcher-website>strong{padding-left:13px}.store-switcher-store{margin:1px 0 0}.store-switcher-store>strong{padding-left:20px}.store-switcher-store>ul{margin-top:1px}.store-switcher-store-view:first-child{border-top:1px solid #e5e5e5}.store-switcher-store-view>a{color:#333;display:block;font-size:13px;padding:5px 15px 5px 24px;text-decoration:none}.store-view:not(.store-switcher){float:left}.store-view .store-switcher-label{display:inline-block;margin-top:1rem}.tooltip{margin-left:.5em}.tooltip .help a,.tooltip .help span{cursor:pointer;display:inline-block;height:22px;position:relative;vertical-align:middle;width:22px;z-index:2}.tooltip .help a:before,.tooltip .help span:before{color:#333;content:'\e633';font-size:1.7rem}.tooltip .help a:hover{text-decoration:none}.tooltip .tooltip-content{background:#000;border-radius:3px;color:#fff;display:none;margin-left:-19px;margin-top:10px;max-width:200px;padding:4px 8px;position:absolute;text-shadow:none;z-index:20}.tooltip .tooltip-content:before{border-bottom:5px solid #000;border-left:5px solid transparent;border-right:5px solid transparent;content:'';height:0;left:20px;opacity:.8;position:absolute;top:-5px;width:0}.tooltip .tooltip-content.loading{position:absolute}.tooltip .tooltip-content.loading:before{border-bottom-color:rgba(0,0,0,.3)}.tooltip:hover>.tooltip-content{display:block}.page-actions._fixed,.page-main-actions:not(._hidden){background:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;padding:1.5rem}.page-main-actions{margin:0 0 3rem}.page-main-actions._hidden .store-switcher{display:none}.page-main-actions._hidden .page-actions-placeholder{min-height:50px}.page-actions{float:right}.page-main-actions .page-actions._fixed{left:8.8rem;position:fixed;right:0;top:0;z-index:501}.page-main-actions .page-actions._fixed .page-actions-inner:before{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#333;content:attr(data-title);float:left;font-size:2.8rem;margin-top:.3rem;max-width:50%}.page-actions .page-actions-buttons>button,.page-actions>button{float:right;margin-left:1.3rem}.page-actions .page-actions-buttons>button.action-back,.page-actions .page-actions-buttons>button.back,.page-actions>button.action-back,.page-actions>button.back{float:left;-ms-flex-order:-1;order:-1}.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before{content:'\e626';margin-right:.5em;position:relative;top:1px}.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary{-ms-flex-order:2;order:2}.page-actions .page-actions-buttons>button.save:not(.primary),.page-actions>button.save:not(.primary){-ms-flex-order:1;order:1}.page-actions .page-actions-buttons>button.delete,.page-actions>button.delete{-ms-flex-order:-1;order:-1}.page-actions .actions-split{float:right;margin-left:1.3rem;-ms-flex-order:2;order:2}.page-actions .actions-split .dropdown-menu .item{display:block}.page-actions-buttons{float:right;-ms-flex-pack:end;justify-content:flex-end;display:-ms-flexbox;display:flex}.customer-index-edit .page-actions-buttons{background-color:transparent}.admin__page-nav{background:#f1f1f1;border:1px solid #e3e3e3}.admin__page-nav._collapsed:first-child{border-bottom:none}.admin__page-nav._collapsed._show{border-bottom:1px solid #e3e3e3}.admin__page-nav._collapsed._show ._collapsible{background:#f1f1f1}.admin__page-nav._collapsed._show ._collapsible:after{content:'\e62b'}.admin__page-nav._collapsed._show ._collapsible+.admin__page-nav-items{display:block}.admin__page-nav._collapsed._hide .admin__page-nav-title-messages,.admin__page-nav._collapsed._hide .admin__page-nav-title-messages ._active{display:inline-block}.admin__page-nav+._collapsed{border-bottom:none;border-top:none}.admin__page-nav-title{border-bottom:1px solid #e3e3e3;color:#303030;display:block;font-size:1.4rem;line-height:1.2;margin:0 0 -1px;padding:1.8rem 1.5rem;position:relative;text-transform:uppercase}.admin__page-nav-title._collapsible{background:#fff;cursor:pointer;margin:0;padding-right:3.5rem;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-title._collapsible+.admin__page-nav-items{display:none;margin-top:-1px}.admin__page-nav-title._collapsible:after{content:'\e628';font-size:1.3rem;font-weight:700;position:absolute;right:1.8rem;top:2rem}.admin__page-nav-title._collapsible:hover{background:#f1f1f1}.admin__page-nav-title._collapsible:last-child{margin:0 0 -1px}.admin__page-nav-title strong{font-weight:700}.admin__page-nav-title .admin__page-nav-title-messages{display:none}.admin__page-nav-items{list-style-type:none;margin:0;padding:1rem 0 1.3rem}.admin__page-nav-item{border-left:3px solid transparent;margin-left:.7rem;padding:0;position:relative;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-item:hover{border-color:#e4e4e4}.admin__page-nav-item:hover .admin__page-nav-link{background:#e4e4e4;color:#303030;text-decoration:none}.admin__page-nav-item._active,.admin__page-nav-item.ui-state-active{border-color:#eb5202}.admin__page-nav-item._active .admin__page-nav-link,.admin__page-nav-item.ui-state-active .admin__page-nav-link{background:#fff;border-color:#e3e3e3;border-right:1px solid #fff;color:#303030;margin-right:-1px;font-weight:600}.admin__page-nav-item._loading:before,.admin__page-nav-item.ui-tabs-loading:before{display:none}.admin__page-nav-item._loading .admin__page-nav-item-message-loader,.admin__page-nav-item.ui-tabs-loading .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-link{border:1px solid transparent;border-width:1px 0;color:#303030;display:block;font-weight:500;line-height:1.2;margin:0 0 -1px;padding:2rem 4rem 2rem 1rem;transition:border-color .1s ease-out,background-color .1s ease-out;word-wrap:break-word}.admin__page-nav-item-messages{display:inline-block}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-size:1.4rem;font-weight:400;left:-1rem;line-height:1.36;padding:1.5rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after,.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf;margin-top:1px}.admin__page-nav-item-message-loader{display:none;margin-top:-1rem;position:absolute;right:0;top:50%}.admin__page-nav-item-message-loader .spinner{font-size:2rem;margin-right:1.5rem}._loading>.admin__page-nav-item-messages .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-item-message{position:relative}.admin__page-nav-item-message:hover{z-index:500}.admin__page-nav-item-message:hover .admin__page-nav-item-message-tooltip{display:block}.admin__page-nav-item-message._changed,.admin__page-nav-item-message._error{display:none}.admin__page-nav-item-message .admin__page-nav-item-message-icon{display:inline-block;font-size:1.4rem;padding-left:.8em;vertical-align:baseline}.admin__page-nav-item-message .admin__page-nav-item-message-icon:after{color:#666;content:'\e631'}._changed:not(._error)>.admin__page-nav-item-messages ._changed{display:inline-block}._error .admin__page-nav-item-message-icon:after{color:#eb5202;content:'\e623'}._error>.admin__page-nav-item-messages ._error{display:inline-block}._error>.admin__page-nav-item-messages ._error .spinner{font-size:2rem;margin-right:1.5rem}._error .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;left:-1rem;line-height:1.36;padding:2rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}._error .admin__page-nav-item-message-tooltip:after,._error .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}._error .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}._error .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf}.admin__data-grid-wrap-static .data-grid{box-sizing:border-box}.admin__data-grid-wrap-static .data-grid thead{color:#333}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td{background-color:#f5f5f5}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td._dragging{background-color:rgba(245,245,245,.95)}.admin__data-grid-wrap-static .data-grid ul{margin-left:1rem;padding-left:1rem}.admin__data-grid-wrap-static .admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-wrap-static .admin__data-grid-loading-mask .grid-loader{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-filters-actions-wrap{float:right}.data-grid-search-control-wrap{float:left;max-width:45.5rem;position:relative;width:35%}.data-grid-search-control-wrap :-ms-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-webkit-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-moz-placeholder{font-style:italic}.data-grid-search-control-wrap .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:.6rem 2rem .2rem;position:absolute;right:0;top:1px}.data-grid-search-control-wrap .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.data-grid-search-control-wrap .action-submit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.data-grid-search-control-wrap .action-submit:hover:before{color:#1a1a1a}._keyfocus .data-grid-search-control-wrap .action-submit:focus{box-shadow:0 0 0 1px #008bdb}.data-grid-search-control-wrap .action-submit:before{content:'\e60c';font-size:2rem;transition:color .1s linear}.data-grid-search-control-wrap .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.data-grid-search-control-wrap .abs-action-menu .action-submenu,.data-grid-search-control-wrap .abs-action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .action-menu,.data-grid-search-control-wrap .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:19.25rem;overflow-y:auto;z-index:398}.data-grid-search-control-wrap .action-menu-item._selected{background-color:#e0f6fe}.data-grid-search-control-wrap .data-grid-search-label{display:none}.data-grid-search-control{padding-right:6rem;width:100%}.data-grid-filters-action-wrap{float:left;padding-left:2rem}.data-grid-filters-action-wrap .action-default{font-size:1.3rem;margin-bottom:1rem;padding-left:1.7rem;padding-right:2.1rem;padding-top:.7rem}.data-grid-filters-action-wrap .action-default._active{background-color:#fff;border-bottom-color:#fff;border-right-color:#ccc;font-weight:600;margin:-.1rem 0 0;padding-bottom:1.6rem;padding-top:.8rem;position:relative;z-index:281}.data-grid-filters-action-wrap .action-default._active:after{background-color:#eb5202;bottom:100%;content:'';height:3px;left:-1px;position:absolute;right:-1px}.data-grid-filters-action-wrap .action-default:before{color:#333;content:'\e605';font-size:1.8rem;margin-right:.4rem;position:relative;top:-1px;vertical-align:top}.data-grid-filters-action-wrap .filters-active{display:none}.admin__action-grid-select .admin__control-select{margin:-.5rem .5rem 0 0;padding-bottom:.6rem;padding-top:.6rem}.admin__data-grid-filters-wrap{opacity:0;visibility:hidden;clear:both;font-size:1.3rem;transition:opacity .3s ease}.admin__data-grid-filters-wrap._show{opacity:1;visibility:visible;border-bottom:1px solid #ccc;border-top:1px solid #ccc;margin-bottom:.7rem;padding:3.6rem 0 3rem;position:relative;top:-1px;z-index:280}.admin__data-grid-filters-wrap._show .admin__data-grid-filters,.admin__data-grid-filters-wrap._show .admin__data-grid-filters-footer{display:block}.admin__data-grid-filters-wrap .admin__form-field-label,.admin__data-grid-filters-wrap .admin__form-field-legend{display:block;font-weight:700;margin:0 0 .3rem;text-align:left}.admin__data-grid-filters-wrap .admin__form-field{display:inline-block;margin-bottom:2em;margin-left:0;padding-left:2rem;padding-right:2rem;vertical-align:top;width:calc(100% / 4 - 4px)}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field{display:block;float:none;margin-bottom:1.5rem;padding-left:0;padding-right:0;width:auto}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field:last-child{margin-bottom:0}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-label{border:1px solid transparent;float:left;font-weight:400;line-height:1.36;margin-bottom:0;padding-bottom:.6rem;padding-right:1em;padding-top:.6rem;width:25%}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-control{margin-left:25%}.admin__data-grid-filters-wrap .admin__action-multiselect,.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text,.admin__data-grid-filters-wrap .admin__form-field-label{font-size:1.3rem}.admin__data-grid-filters-wrap .admin__control-select{height:3.2rem;padding-top:.5rem}.admin__data-grid-filters-wrap .admin__action-multiselect:before{height:3.2rem;width:3.2rem}.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text._has-datepicker{width:100%}.admin__data-grid-filters{display:none;margin-left:-2rem;margin-right:-2rem}.admin__filters-legend{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-filters-footer{display:none;font-size:1.4rem}.admin__data-grid-filters-footer .admin__footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-filters-footer .admin__footer-secondary-actions{float:left;width:50%}.admin__data-grid-filters-current{border-bottom:.1rem solid #ccc;border-top:.1rem solid #ccc;display:none;font-size:1.3rem;margin-bottom:.9rem;padding-bottom:.8rem;padding-top:1.1rem;width:100%}.admin__data-grid-filters-current._show{display:table;position:relative;top:-1px;z-index:3}.admin__data-grid-filters-current._show+.admin__data-grid-filters-wrap._show{margin-top:-1rem}.admin__current-filters-actions-wrap,.admin__current-filters-list-wrap,.admin__current-filters-title-wrap{display:table-cell;vertical-align:top}.admin__current-filters-title{margin-right:1em;white-space:nowrap}.admin__current-filters-list-wrap{width:100%}.admin__current-filters-list{margin-bottom:0}.admin__current-filters-list>li{display:inline-block;font-weight:600;margin:0 1rem .5rem;padding-right:2.6rem;position:relative}.admin__current-filters-list .action-remove{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0;line-height:1;position:absolute;right:0;top:1px}.admin__current-filters-list .action-remove:hover{background-color:transparent;border:none;box-shadow:none}.admin__current-filters-list .action-remove:hover:before{color:#949494}.admin__current-filters-list .action-remove:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__current-filters-list .action-remove:before{color:#adadad;content:'\e620';font-size:1.6rem;transition:color .1s linear}.admin__current-filters-list .action-remove>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__current-filters-actions-wrap .action-clear{border:none;padding-bottom:0;padding-top:0;white-space:nowrap}.admin__data-grid-pager-wrap{float:right;text-align:right}.admin__data-grid-pager{display:inline-block;margin-left:3rem}.admin__data-grid-pager .admin__control-text::-webkit-inner-spin-button,.admin__data-grid-pager .admin__control-text::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.admin__data-grid-pager .admin__control-text{-moz-appearance:textfield;text-align:center;width:4.4rem}.action-next,.action-previous{width:4.4rem}.action-next:before,.action-previous:before{font-weight:700}.action-next>span,.action-previous>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-previous{margin-right:2.5rem;text-indent:-.25em}.action-previous:before{content:'\e629'}.action-next{margin-left:1.5rem;text-indent:.1em}.action-next:before{content:'\e62a'}.admin__data-grid-action-bookmarks{opacity:.98}.admin__data-grid-action-bookmarks .admin__action-dropdown-text:after{left:0;right:-6px}.admin__data-grid-action-bookmarks._active{z-index:290}.admin__data-grid-action-bookmarks .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:15rem;min-width:4.9rem;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown:before{content:'\e60f'}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu{font-size:1.3rem;left:0;padding:1rem 0;right:auto}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li{padding:0 5rem 0 0;position:relative;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action){transition:background-color .1s linear}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action):hover{background-color:#e3e3e3}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item{max-width:23rem;min-width:18rem;white-space:normal;word-break:break-all}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit{display:none;padding-bottom:1rem;padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit .action-dropdown-menu-item-actions{padding-bottom:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action{padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action+.action-dropdown-menu-item-last{padding-top:.5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a{color:#008bdb;text-decoration:none;display:inline-block;padding-left:1.1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a:hover{color:#0fa7ff;text-decoration:underline}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-last{padding-bottom:0}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item{display:none}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item-edit{display:block}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._active .action-dropdown-menu-link{font-weight:600}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{font-size:1.3rem;min-width:15rem;width:calc(100% - 4rem)}.ie9 .admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{width:15rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-actions{border-left:1px solid #fff;bottom:0;position:absolute;right:0;top:0;width:5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-link{color:#333;display:block;text-decoration:none;padding:1rem 1rem 1rem 2.1rem}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit,.admin__data-grid-action-bookmarks .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;vertical-align:top}.admin__data-grid-action-bookmarks .action-delete:hover,.admin__data-grid-action-bookmarks .action-edit:hover,.admin__data-grid-action-bookmarks .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before{font-size:1.7rem}.admin__data-grid-action-bookmarks .action-delete>span,.admin__data-grid-action-bookmarks .action-edit>span,.admin__data-grid-action-bookmarks .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit{padding:.6rem 1.4rem}.admin__data-grid-action-bookmarks .action-delete:active,.admin__data-grid-action-bookmarks .action-edit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__data-grid-action-bookmarks .action-submit{padding:.6rem 1rem .6rem .8rem}.admin__data-grid-action-bookmarks .action-submit:active{position:relative;right:-1px}.admin__data-grid-action-bookmarks .action-submit:before{content:'\e625'}.admin__data-grid-action-bookmarks .action-delete:before{content:'\e630'}.admin__data-grid-action-bookmarks .action-edit{padding-top:.8rem}.admin__data-grid-action-bookmarks .action-edit:before{content:'\e631'}.admin__data-grid-action-columns._active{opacity:.98;z-index:290}.admin__data-grid-action-columns .admin__action-dropdown:before{content:'\e610';font-size:1.8rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-columns-menu{color:#303030;font-size:1.3rem;overflow:hidden;padding:2.2rem 3.5rem 1rem;z-index:1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-header{border-bottom:1px solid #d1d1d1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-content{width:49.2rem}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-footer{border-top:1px solid #d1d1d1;padding-top:2.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content{max-height:22.85rem;overflow-y:auto;padding-top:1.5rem;position:relative;width:47.4rem}.admin__data-grid-action-columns-menu .admin__field-option{float:left;height:1.9rem;margin-bottom:1.5rem;padding:0 1rem 0 0;width:15.8rem}.admin__data-grid-action-columns-menu .admin__field-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-header{padding-bottom:1.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-footer{padding:1rem 0 2rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-secondary-actions{float:left;margin-left:-1em}.admin__data-grid-action-export._active{opacity:.98;z-index:290}.admin__data-grid-action-export .admin__action-dropdown:before{content:'\e635';font-size:1.7rem;left:.3rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-export-menu{padding-left:2rem;padding-right:2rem;padding-top:1rem}.admin__data-grid-action-export-menu .admin__action-dropdown-footer-main-actions{padding-bottom:2rem;padding-top:2.5rem;white-space:nowrap}.sticky-header{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:8.8rem;margin-top:-1px;padding:.5rem 3rem 0;position:fixed;right:0;top:77px;z-index:398}.sticky-header .admin__data-grid-wrap{margin-bottom:0;overflow-x:visible;padding-bottom:0}.sticky-header .admin__data-grid-header-row{position:relative;text-align:right}.sticky-header .admin__data-grid-header-row:last-child{margin:0}.sticky-header .admin__data-grid-actions-wrap,.sticky-header .admin__data-grid-filters-wrap,.sticky-header .admin__data-grid-pager-wrap,.sticky-header .data-grid-filters-actions-wrap,.sticky-header .data-grid-search-control-wrap{display:inline-block;float:none;vertical-align:top}.sticky-header .action-select-wrap{float:left;margin-right:1.5rem;width:16.66666667%}.sticky-header .admin__control-support-text{float:left}.sticky-header .data-grid-search-control-wrap{margin:-.5rem 0 0 1.1rem;width:auto}.sticky-header .data-grid-search-control-wrap .data-grid-search-label{box-sizing:border-box;cursor:pointer;display:block;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;position:relative;text-align:center}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before{color:#333;content:'\e60c';font-size:2rem;transition:color .1s linear}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:hover:before{color:#000}.sticky-header .data-grid-search-control-wrap .data-grid-search-label span{display:none}.sticky-header .data-grid-filters-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-left:0;position:relative}.sticky-header .data-grid-filters-actions-wrap .action-default{background-color:transparent;border:1px solid transparent;box-sizing:border-box;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;text-align:center;transition:all .15s ease}.sticky-header .data-grid-filters-actions-wrap .action-default span{display:none}.sticky-header .data-grid-filters-actions-wrap .action-default:before{margin:0}.sticky-header .data-grid-filters-actions-wrap .action-default._active{background-color:#fff;border-color:#adadad #adadad #fff;box-shadow:1px 1px 5px rgba(0,0,0,.5);z-index:210}.sticky-header .data-grid-filters-actions-wrap .action-default._active:after{background-color:#fff;content:'';height:6px;left:-2px;position:absolute;right:-6px;top:100%}.sticky-header .data-grid-filters-action-wrap{padding:0}.sticky-header .admin__data-grid-filters-wrap{background-color:#fff;border:1px solid #adadad;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:0;padding-left:3.5rem;padding-right:3.5rem;position:absolute;top:100%;width:100%;z-index:209}.sticky-header .admin__data-grid-filters-current+.admin__data-grid-filters-wrap._show{margin-top:-6px}.sticky-header .filters-active{background-color:#e04f00;border-radius:10px;color:#fff;display:block;font-size:1.4rem;font-weight:700;padding:.1rem .7rem;position:absolute;right:-7px;top:0;z-index:211}.sticky-header .filters-active:empty{padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-right:.3rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown{background-color:transparent;box-sizing:border-box;min-width:3.8rem;padding-left:.6rem;padding-right:.6rem;text-align:center}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:0;min-width:0;overflow:hidden}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:before{margin:0}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap{margin-right:1.1rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after,.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:after{display:none}.sticky-header .admin__data-grid-actions-wrap ._active .admin__action-dropdown{background-color:#fff}.sticky-header .admin__data-grid-action-bookmarks .admin__action-dropdown:before{position:relative;top:-3px}.sticky-header .admin__data-grid-filters-current{border-bottom:0;border-top:0;margin-bottom:0;padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-pager .admin__control-text,.sticky-header .admin__data-grid-pager-wrap .admin__control-support-text,.sticky-header .data-grid-search-control-wrap .action-submit,.sticky-header .data-grid-search-control-wrap .data-grid-search-control{display:none}.sticky-header .action-next{margin:0}.sticky-header .data-grid{margin-bottom:-1px}.data-grid-cap-left,.data-grid-cap-right{background-color:#f8f8f8;bottom:-2px;position:absolute;top:6rem;width:3rem;z-index:201}.data-grid-cap-left{left:0}.admin__data-grid-header{font-size:1.4rem}.admin__data-grid-header-row+.admin__data-grid-header-row{margin-top:1.1rem}.admin__data-grid-header-row:last-child{margin-bottom:0}.admin__data-grid-header-row .action-select-wrap{display:block}.admin__data-grid-header-row .action-select{width:100%}.admin__data-grid-actions-wrap{float:right;margin-left:1.1rem;margin-top:-.5rem;text-align:right}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap{position:relative;text-align:left;vertical-align:middle}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._hide+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:first-child:after{display:none}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown-menu{border-color:#adadad}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after{border-left:1px solid #ccc;content:'';height:3.2rem;left:0;position:absolute;top:.5rem;z-index:3}.admin__data-grid-actions-wrap .admin__action-dropdown{padding-bottom:1.7rem;padding-top:1.2rem}.admin__data-grid-actions-wrap .admin__action-dropdown:after{margin-top:-.4rem}.admin__data-grid-outer-wrap{min-height:8rem;position:relative}.admin__data-grid-wrap{margin-bottom:2rem;max-width:100%;overflow-x:auto;padding-bottom:1rem;padding-top:2rem}.admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-loading-mask .spinner{font-size:4rem;left:50%;margin-left:-2rem;margin-top:-2rem;position:absolute;top:50%}.ie9 .admin__data-grid-loading-mask .spinner{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-cell-content{display:inline-block;overflow:hidden;width:100%}body._in-resize{cursor:col-resize;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body._in-resize *,body._in-resize .data-grid-th,body._in-resize .data-grid-th._draggable,body._in-resize .data-grid-th._sortable{cursor:col-resize!important}._layout-fixed{table-layout:fixed}.data-grid{border:none;font-size:1.3rem;margin-bottom:0;width:100%}.data-grid:not(._dragging-copy) ._odd-row td._dragging{background-color:#d0d0d0}.data-grid:not(._dragging-copy) ._dragging{background-color:#d9d9d9;color:rgba(48,48,48,.95)}.data-grid:not(._dragging-copy) ._dragging a{color:rgba(0,139,219,.95)}.data-grid:not(._dragging-copy) ._dragging a:hover{color:rgba(15,167,255,.95)}.data-grid._dragged{outline:#007bdb solid 1px}.data-grid thead{background-color:transparent}.data-grid tfoot th{padding:1rem}.data-grid tr._odd-row td{background-color:#f5f5f5}.data-grid tr._odd-row td._update-status-active{background:#89e1ff}.data-grid tr._odd-row td._update-status-upcoming{background:#b7ee63}.data-grid tr:hover td._update-status-active,.data-grid tr:hover td._update-status-upcoming{background-color:#e5f7fe}.data-grid tr.data-grid-tr-no-data td{font-size:1.6rem;padding:3rem;text-align:center}.data-grid tr.data-grid-tr-no-data:hover td{background-color:#fff;cursor:default}.data-grid tr:active td{background-color:#e0f6fe}.data-grid tr:hover td{background-color:#e5f7fe}.data-grid tr._dragged td{background:#d0d0d0}.data-grid tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.data-grid tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.data-grid tr:not(.data-grid-editable-row):last-child td{border-bottom:.1rem solid #d6d6d6}.data-grid tr ._clickable,.data-grid tr._clickable{cursor:pointer}.data-grid tr._disabled{pointer-events:none}.data-grid td,.data-grid th{font-size:1.3rem;line-height:1.36;transition:background-color .1s linear;vertical-align:top}.data-grid td._resizing,.data-grid th._resizing{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid td._hidden,.data-grid th._hidden{display:none}.data-grid td._fit,.data-grid th._fit{width:1%}.data-grid td{background-color:#fff;border-left:.1rem dashed #d6d6d6;border-right:.1rem dashed #d6d6d6;color:#303030;padding:1rem}.data-grid td:first-child{border-left-style:solid}.data-grid td:last-child{border-right-style:solid}.data-grid td .action-select-wrap{position:static}.data-grid td .action-select{color:#008bdb;text-decoration:none;background-color:transparent;border:none;font-size:1.3rem;padding:0 3rem 0 0;position:relative}.data-grid td .action-select:hover{color:#0fa7ff;text-decoration:underline}.data-grid td .action-select:hover:after{border-color:#0fa7ff transparent transparent}.data-grid td .action-select:after{border-color:#008bdb transparent transparent;margin:.6rem 0 0 .7rem;right:auto;top:auto}.data-grid td .action-select:before{display:none}.data-grid td .abs-action-menu .action-submenu,.data-grid td .abs-action-menu .action-submenu .action-submenu,.data-grid td .action-menu,.data-grid td .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:10rem;right:0;text-align:left;top:auto;z-index:1}.data-grid td._update-status-active{background:#bceeff}.data-grid td._update-status-upcoming{background:#ccf391}.data-grid th{background-color:#514943;border:.1rem solid #8a837f;border-left-color:transparent;color:#fff;font-weight:600;padding:0;text-align:left}.data-grid th:first-child{border-left-color:#8a837f}.data-grid th._dragover-left{box-shadow:inset 3px 0 0 0 #fff;z-index:2}.data-grid th._dragover-right{box-shadow:inset -3px 0 0 0 #fff}.data-grid .shadow-div{cursor:col-resize;height:100%;margin-right:-5px;position:absolute;right:0;top:0;width:10px}.data-grid .data-grid-th{background-clip:padding-box;color:#fff;padding:1rem;position:relative;vertical-align:middle}.data-grid .data-grid-th._resize-visible .shadow-div{cursor:auto;display:none}.data-grid .data-grid-th._draggable{cursor:grab}.data-grid .data-grid-th._sortable{cursor:pointer;transition:background-color .1s linear;z-index:1}.data-grid .data-grid-th._sortable:focus,.data-grid .data-grid-th._sortable:hover{background-color:#5f564f}.data-grid .data-grid-th._sortable:active{padding-bottom:.9rem;padding-top:1.1rem}.data-grid .data-grid-th.required>span:after{color:#f38a5e;content:'*';margin-left:.3rem}.data-grid .data-grid-checkbox-cell{overflow:hidden;padding:0;vertical-align:top;width:5.2rem}.data-grid .data-grid-checkbox-cell:hover{cursor:default}.data-grid .data-grid-thumbnail-cell{text-align:center;width:7rem}.data-grid .data-grid-thumbnail-cell img{border:1px solid #d6d6d6;width:5rem}.data-grid .data-grid-multicheck-cell{padding:1rem 1rem .9rem;text-align:center;vertical-align:middle}.data-grid .data-grid-onoff-cell{text-align:center;width:12rem}.data-grid .data-grid-actions-cell{padding-left:2rem;padding-right:2rem;text-align:center;width:1%}.data-grid._hidden{display:none}.data-grid._dragging-copy{box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;opacity:.95;position:fixed;top:0;z-index:1000}.data-grid._dragging-copy .data-grid-th{border:1px solid #007bdb;border-bottom:none}.data-grid._dragging-copy .data-grid-th,.data-grid._dragging-copy .data-grid-th._sortable{cursor:grabbing}.data-grid._dragging-copy tr:last-child td{border-bottom:1px solid #007bdb}.data-grid._dragging-copy td{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:rgba(255,251,230,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td,.data-grid._dragging-copy._in-edit .data-grid-editable-row:hover td{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:after,.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{left:0;right:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:only-child{border-left:1px solid #007bdb;border-right:1px solid #007bdb;left:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-select,.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-text{opacity:.5}.data-grid .data-grid-controls-row td{padding-top:1.6rem}.data-grid .data-grid-controls-row td.data-grid-checkbox-cell{padding-top:.6rem}.data-grid .data-grid-controls-row td [class*=admin__control-],.data-grid .data-grid-controls-row td button{margin-top:-1.7rem}.data-grid._in-edit tr:hover td{background-color:#e6e6e6}.data-grid._in-edit ._odd-row.data-grid-editable-row td,.data-grid._in-edit ._odd-row.data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit ._odd-row td,.data-grid._in-edit ._odd-row:hover td{background-color:#dcdcdc}.data-grid._in-edit .data-grid-editable-row-actions td,.data-grid._in-edit .data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid._in-edit td{background-color:#e6e6e6;pointer-events:none}.data-grid._in-edit .data-grid-checkbox-cell{pointer-events:auto}.data-grid._in-edit .data-grid-editable-row{border:.1rem solid #adadad;border-bottom-color:#c2c2c2}.data-grid._in-edit .data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit .data-grid-editable-row td{background-color:#fff;border-bottom-color:#fff;border-left-style:hidden;border-right-style:hidden;border-top-color:#fff;pointer-events:auto;vertical-align:middle}.data-grid._in-edit .data-grid-editable-row td:first-child{border-left-color:#adadad;border-left-style:solid}.data-grid._in-edit .data-grid-editable-row td:first-child:after,.data-grid._in-edit .data-grid-editable-row td:first-child:before{left:0}.data-grid._in-edit .data-grid-editable-row td:last-child{border-right-color:#adadad;border-right-style:solid;left:-.1rem}.data-grid._in-edit .data-grid-editable-row td:last-child:after,.data-grid._in-edit .data-grid-editable-row td:last-child:before{right:0}.data-grid._in-edit .data-grid-editable-row .admin__control-select,.data-grid._in-edit .data-grid-editable-row .admin__control-text{width:100%}.data-grid._in-edit .data-grid-bulk-edit-panel td{vertical-align:bottom}.data-grid .data-grid-editable-row td{border-left-color:#fff;border-left-style:solid;position:relative;z-index:1}.data-grid .data-grid-editable-row td:after{bottom:0;box-shadow:0 5px 5px rgba(0,0,0,.25);content:'';height:.9rem;left:0;margin-top:-1rem;position:absolute;right:0}.data-grid .data-grid-editable-row td:before{background-color:#fff;bottom:0;content:'';height:1rem;left:-10px;position:absolute;right:-10px;z-index:1}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td,.data-grid .data-grid-editable-row.data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:first-child{border-left-color:#fff;border-right-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:last-child{left:0}.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:#fffbe6}.data-grid .data-grid-editable-row-actions{left:50%;margin-left:-12.5rem;margin-top:-2px;position:absolute;text-align:center}.data-grid .data-grid-editable-row-actions td{width:25rem}.data-grid .data-grid-editable-row-actions [class*=action-]{min-width:9rem}.data-grid .data-grid-draggable-row-cell{width:1%}.data-grid .data-grid-draggable-row-cell .draggable-handle{padding:0}.data-grid-th._sortable._ascend,.data-grid-th._sortable._descend{padding-right:2.7rem}.data-grid-th._sortable._ascend:before,.data-grid-th._sortable._descend:before{margin-top:-1em;position:absolute;right:1rem;top:50%}.data-grid-th._sortable._ascend:before{content:'\2193'}.data-grid-th._sortable._descend:before{content:'\2191'}.data-grid-checkbox-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:right}.data-grid-checkbox-cell-inner:hover{cursor:pointer}.data-grid-state-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:center}.data-grid-state-cell-inner>span{display:inline-block;font-style:italic;padding:.6rem 0}.data-grid-row-parent._active>td .data-grid-checkbox-cell-inner:before{content:'\e62b'}.data-grid-row-parent>td .data-grid-checkbox-cell-inner{padding-left:3.7rem;position:relative}.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before{content:'\e628';font-size:1rem;font-weight:700;left:1.35rem;position:absolute;top:1.6rem}.data-grid-th._col-xs{width:1%}.data-grid-info-panel{box-shadow:0 0 5px rgba(0,0,0,.5);margin:2rem .1rem -2rem}.data-grid-info-panel .messages{overflow:hidden}.data-grid-info-panel .messages .message{margin:1rem}.data-grid-info-panel .messages .message:last-child{margin-bottom:1rem}.data-grid-info-panel-actions{padding:1rem;text-align:right}.data-grid-editable-row .admin__field-control{position:relative}.data-grid-editable-row .admin__field-control._error:after{border-color:transparent #ee7d7d transparent transparent;border-style:solid;border-width:0 12px 12px 0;content:'';position:absolute;right:0;top:0}.data-grid-editable-row .admin__field-control._error .admin__control-text{border-color:#ee7d7d}.data-grid-editable-row .admin__field-control._focus:after{display:none}.data-grid-editable-row .admin__field-error{bottom:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin:0 auto 1.5rem;max-width:32rem;position:absolute;right:0}.data-grid-editable-row .admin__field-error:after,.data-grid-editable-row .admin__field-error:before{border-style:solid;content:'';left:50%;position:absolute;top:100%}.data-grid-editable-row .admin__field-error:after{border-color:#fffbbb transparent transparent;border-width:10px 10px 0;margin-left:-10px;z-index:1}.data-grid-editable-row .admin__field-error:before{border-color:#ee7d7d transparent transparent;border-width:11px 12px 0;margin-left:-12px}.data-grid-bulk-edit-panel .admin__field-label-vertical{display:block;font-size:1.2rem;margin-bottom:.5rem;text-align:left}.data-grid-row-changed{cursor:default;display:block;opacity:.5;position:relative;width:100%;z-index:1}.data-grid-row-changed:after{content:'\e631';display:inline-block}.data-grid-row-changed .data-grid-row-changed-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:100%;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;line-height:1.36;margin-bottom:1.5rem;padding:1rem;position:absolute;right:-1rem;text-transform:none;width:27rem;word-break:normal;z-index:2}.data-grid-row-changed._changed{opacity:1;z-index:3}.data-grid-row-changed._changed:hover .data-grid-row-changed-tooltip{display:block}.data-grid-row-changed._changed:hover:before{background:#f1f1f1;border:1px solid #f1f1f1;bottom:100%;box-shadow:4px 4px 3px -1px rgba(0,0,0,.15);content:'';display:block;height:1.6rem;left:50%;margin:0 0 .7rem -.8rem;position:absolute;-ms-transform:rotate(45deg);transform:rotate(45deg);width:1.6rem;z-index:3}.ie9 .data-grid-row-changed._changed:hover:before{display:none}.admin__data-grid-outer-wrap .data-grid-checkbox-cell{overflow:hidden}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner{position:relative}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner:before{bottom:0;content:'';height:500%;left:0;position:absolute;right:0;top:0}.admin__data-grid-wrap-static .data-grid-checkbox-cell:hover{cursor:pointer}.admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:1.1rem 1.8rem .9rem;padding:0}.adminhtml-cms-hierarchy-index .admin__data-grid-wrap-static .data-grid-actions-cell:first-child{padding:0}.adminhtml-export-index .admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:0;padding:1.1rem 1.8rem 1.9rem}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before,.admin__control-file-label:before,.admin__control-multiselect,.admin__control-select,.admin__control-text,.admin__control-textarea,.selectmenu{-webkit-appearance:none;background-color:#fff;border:1px solid #adadad;border-radius:1px;box-shadow:none;color:#303030;font-size:1.4rem;font-weight:400;height:auto;line-height:1.36;padding:.6rem 1rem;transition:border-color .1s linear;vertical-align:baseline;width:auto}.admin__control-addon [class*=admin__control-][class]:hover~[class*=admin__addon-]:last-child:before,.admin__control-multiselect:hover,.admin__control-select:hover,.admin__control-text:hover,.admin__control-textarea:hover,.selectmenu:hover,.selectmenu:hover .selectmenu-toggle:before{border-color:#878787}.admin__control-addon [class*=admin__control-][class]:focus~[class*=admin__addon-]:last-child:before,.admin__control-file:active+.admin__control-file-label:before,.admin__control-file:focus+.admin__control-file-label:before,.admin__control-multiselect:focus,.admin__control-select:focus,.admin__control-text:focus,.admin__control-textarea:focus,.selectmenu._focus,.selectmenu._focus .selectmenu-toggle:before{border-color:#007bdb;box-shadow:none;outline:0}.admin__control-addon [class*=admin__control-][class][disabled]~[class*=admin__addon-]:last-child:before,.admin__control-file[disabled]+.admin__control-file-label:before,.admin__control-multiselect[disabled],.admin__control-select[disabled],.admin__control-text[disabled],.admin__control-textarea[disabled]{background-color:#e9e9e9;border-color:#adadad;color:#303030;cursor:not-allowed;opacity:.5}.admin__field-row[class]>.admin__field-control,.admin__fieldset>.admin__field.admin__field-wide[class]>.admin__field-control{clear:left;float:none;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label{display:block;line-height:1.4rem;margin-bottom:.86rem;margin-top:-.14rem;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label:before,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label:before{display:none}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span{padding-left:1.5rem}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span:after{left:0;margin-left:30px}.admin__legend{font-size:1.8rem;font-weight:600;margin-bottom:3rem}.admin__control-checkbox,.admin__control-radio{cursor:pointer;opacity:.01;overflow:hidden;position:absolute;vertical-align:top}.admin__control-checkbox:after,.admin__control-radio:after{display:none}.admin__control-checkbox+label,.admin__control-radio+label{cursor:pointer;display:inline-block}.admin__control-checkbox+label:before,.admin__control-radio+label:before{background-color:#fff;border:1px solid #adadad;color:transparent;float:left;height:1.6rem;text-align:center;vertical-align:top;width:1.6rem}.admin__control-checkbox+.admin__field-label,.admin__control-radio+.admin__field-label{padding-left:2.6rem}.admin__control-checkbox+.admin__field-label:before,.admin__control-radio+.admin__field-label:before{margin:1px 1rem 0 -2.6rem}.admin__control-checkbox:checked+label:before,.admin__control-radio:checked+label:before{color:#514943}.admin__control-checkbox.disabled+label,.admin__control-checkbox[disabled]+label,.admin__control-radio.disabled+label,.admin__control-radio[disabled]+label{color:#303030;cursor:default;opacity:.5}.admin__control-checkbox.disabled+label:before,.admin__control-checkbox[disabled]+label:before,.admin__control-radio.disabled+label:before,.admin__control-radio[disabled]+label:before{background-color:#e9e9e9;border-color:#adadad;cursor:default}._keyfocus .admin__control-checkbox:not(.disabled):focus+label:before,._keyfocus .admin__control-checkbox:not([disabled]):focus+label:before,._keyfocus .admin__control-radio:not(.disabled):focus+label:before,._keyfocus .admin__control-radio:not([disabled]):focus+label:before{border-color:#007bdb}.admin__control-checkbox:not(.disabled):hover+label:before,.admin__control-checkbox:not([disabled]):hover+label:before,.admin__control-radio:not(.disabled):hover+label:before,.admin__control-radio:not([disabled]):hover+label:before{border-color:#878787}.admin__control-radio+label:before{border-radius:1.6rem;content:'';transition:border-color .1s linear,color .1s ease-in}.admin__control-radio.admin__control-radio+label:before{line-height:140%}.admin__control-radio:checked+label{position:relative}.admin__control-radio:checked+label:after{background-color:#514943;border-radius:50%;content:'';height:10px;left:3px;position:absolute;top:4px;width:10px}.admin__control-radio:checked:not(.disabled):hover,.admin__control-radio:checked:not(.disabled):hover+label,.admin__control-radio:checked:not([disabled]):hover,.admin__control-radio:checked:not([disabled]):hover+label{cursor:default}.admin__control-radio:checked:not(.disabled):hover+label:before,.admin__control-radio:checked:not([disabled]):hover+label:before{border-color:#adadad}.admin__control-checkbox+label:before{border-radius:1px;content:'';font-size:0;transition:font-size .1s ease-out,color .1s ease-out,border-color .1s linear}.admin__control-checkbox:checked+label:before{content:'\e62d';font-size:1.1rem;line-height:125%}.admin__control-checkbox:not(:checked)._indeterminate+label:before,.admin__control-checkbox:not(:checked):indeterminate+label:before{color:#514943;content:'-';font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700}input[type=checkbox].admin__control-checkbox,input[type=radio].admin__control-checkbox{margin:0;position:absolute}.admin__control-text{min-width:4rem}.admin__control-select{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#adadad,#adadad);background-position:calc(100% - 12px) -34px,100%,calc(100% - 3.2rem) 0;background-size:auto,3.2rem 100%,1px 100%;background-repeat:no-repeat;max-width:100%;min-width:8.5rem;padding-bottom:.5rem;padding-right:4.4rem;padding-top:.5rem;transition:border-color .1s linear}.admin__control-select:hover{border-color:#878787;cursor:pointer}.admin__control-select:focus{background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#007bdb,#007bdb);background-position:calc(100% - 12px) 13px,100%,calc(100% - 3.2rem) 0;border-color:#007bdb}.admin__control-select::-ms-expand{display:none}.ie9 .admin__control-select{background-image:none;padding-right:1rem}option:empty{display:none}.admin__control-multiselect{height:auto;max-width:100%;min-width:15rem;overflow:auto;padding:0;resize:both}.admin__control-multiselect optgroup,.admin__control-multiselect option{padding:.5rem 1rem}.admin__control-file-wrapper{display:inline-block;padding:.5rem 1rem;position:relative;z-index:1}.admin__control-file-label:before{content:'';left:0;position:absolute;top:0;width:100%;z-index:0}.admin__control-file{background:0 0;border:0;padding-top:.7rem;position:relative;width:auto;z-index:1}.admin__control-support-text{border:1px solid transparent;display:inline-block;font-size:1.4rem;line-height:1.36;padding-bottom:.6rem;padding-top:.6rem}.admin__control-support-text+[class*=admin__control-],[class*=admin__control-]+.admin__control-support-text{margin-left:.7rem}.admin__control-service{float:left;margin:.8rem 0 0 3rem}.admin__control-textarea{height:8.48rem;line-height:1.18;padding-top:.8rem;resize:vertical}.admin__control-addon{-ms-flex-direction:row;flex-direction:row;display:inline-flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;position:relative;width:100%;z-index:1}.admin__control-addon>[class*=admin__addon-],.admin__control-addon>[class*=admin__control-]{-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0;position:relative;z-index:1}.admin__control-addon .admin__control-select{width:auto}.admin__control-addon .admin__control-text{margin:.1rem;padding:.5rem .9rem;width:100%}.admin__control-addon [class*=admin__control-][class]{appearence:none;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-order:1;order:1;-ms-flex-negative:1;flex-shrink:1;background-color:transparent;border-color:transparent;box-shadow:none;vertical-align:top}.admin__control-addon [class*=admin__control-][class]+[class*=admin__control-]{border-left-color:#adadad}.admin__control-addon [class*=admin__control-][class] :focus{box-shadow:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child{padding-left:1rem;position:static!important;z-index:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child>*{position:relative;vertical-align:top;z-index:1}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:empty{padding:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before{bottom:0;box-sizing:border-box;content:'';left:0;position:absolute;top:0;width:100%;z-index:-1}.admin__addon-prefix,.admin__addon-suffix{border:0;box-sizing:border-box;color:#858585;display:inline-block;font-size:1.4rem;font-weight:400;height:3.2rem;line-height:3.2rem;padding:0}.admin__addon-suffix{-ms-flex-order:3;order:3}.admin__addon-suffix:last-child{padding-right:1rem}.admin__addon-prefix{-ms-flex-order:0;order:0}.ie9 .admin__control-addon:after{clear:both;content:'';display:block;height:0;overflow:hidden}.ie9 .admin__addon{min-width:0;overflow:hidden;text-align:right;white-space:nowrap;width:auto}.ie9 .admin__addon [class*=admin__control-]{display:inline}.ie9 .admin__addon-prefix{float:left}.ie9 .admin__addon-suffix{float:right}.admin__control-collapsible{width:100%}.admin__control-collapsible ._dragged .admin__collapsible-block-wrapper .admin__collapsible-title{background:#d0d0d0}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before,.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{background:#008bdb;content:'';display:block;height:3px;left:0;position:absolute;right:0}.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{top:-3px}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before{bottom:-3px}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper{border:0;margin:0;position:relative}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper .fieldset-wrapper-title{background:#f8f8f8;border:2px solid #ccc}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title{font-size:1.4rem;font-weight:400;line-height:1;padding:1.6rem 4rem 1.6rem 3.8rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title:before{left:1rem;right:auto;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding:0;position:absolute;right:1rem;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before{content:'\e630';font-size:2rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete>span{display:none}.admin__control-collapsible .admin__collapsible-content{background-color:#fff;margin-bottom:1rem}.admin__control-collapsible .admin__collapsible-content>.fieldset-wrapper{border:1px solid #ccc;margin-top:-1px;padding:1rem}.admin__control-collapsible .admin__collapsible-content .admin__fieldset{padding:0}.admin__control-collapsible .admin__collapsible-content .admin__field:last-child{margin-bottom:0}.admin__control-table-wrapper{max-width:100%;overflow-x:auto;overflow-y:hidden}.admin__control-table{width:100%}.admin__control-table thead{background-color:transparent}.admin__control-table tbody td{vertical-align:top}.admin__control-table tfoot th{padding-bottom:1.3rem}.admin__control-table tfoot th.validation{padding-bottom:0;padding-top:0}.admin__control-table tfoot td{border-top:1px solid #fff}.admin__control-table tfoot .admin__control-table-pagination{float:right;padding-bottom:0}.admin__control-table tfoot .action-previous{margin-right:.5rem}.admin__control-table tfoot .action-next{margin-left:.9rem}.admin__control-table tr:last-child td{border-bottom:none}.admin__control-table tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.admin__control-table tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.admin__control-table tr._dragged td,.admin__control-table tr._dragged th{background:#d0d0d0}.admin__control-table td,.admin__control-table th{background-color:#efefef;border:0;border-bottom:1px solid #fff;padding:1.3rem 1rem 1.3rem 0;text-align:left;vertical-align:top}.admin__control-table td:first-child,.admin__control-table th:first-child{padding-left:1rem}.admin__control-table td>.admin__control-select,.admin__control-table td>.admin__control-text,.admin__control-table th>.admin__control-select,.admin__control-table th>.admin__control-text{width:100%}.admin__control-table td._hidden,.admin__control-table th._hidden{display:none}.admin__control-table td._fit,.admin__control-table th._fit{width:1px}.admin__control-table th{color:#303030;font-size:1.4rem;font-weight:600;vertical-align:bottom}.admin__control-table th._required span:after{color:#eb5202;content:'*'}.admin__control-table .control-table-actions-th{white-space:nowrap}.admin__control-table .control-table-actions-cell{padding-top:1.8rem;text-align:center;width:1%}.admin__control-table .control-table-options-th{text-align:center;width:10rem}.admin__control-table .control-table-options-cell{text-align:center}.admin__control-table .control-table-text{line-height:3.2rem}.admin__control-table .col-draggable{padding-top:2.2rem;width:1%}.admin__control-table .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.admin__control-table .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-table .action-delete:before{content:'\e630';font-size:2rem}.admin__control-table .action-delete>span{display:none}.admin__control-table .draggable-handle{padding:0}.admin__control-table._dragged{outline:#007bdb solid 1px}.admin__control-table-action{background-color:#efefef;border-top:1px solid #fff;padding:1.3rem 1rem}.admin__dynamic-rows._dragged{opacity:.95;position:absolute;z-index:999}.admin__dynamic-rows.admin__control-table .admin__control-fields>.admin__field{border:0;padding:0}.admin__dynamic-rows td>.admin__field{border:0;margin:0;padding:0}.admin__control-table-pagination{padding-bottom:1rem}.admin__control-table-pagination .admin__data-grid-pager{float:right}.admin__field-tooltip{display:inline-block;margin-top:.5rem;max-width:45px;overflow:visible;vertical-align:top;width:0}.admin__field-tooltip:hover{position:relative;z-index:500}.admin__field-option .admin__field-tooltip{margin-top:.5rem}.admin__field-tooltip .admin__field-tooltip-action{margin-left:2rem;position:relative;z-index:2;display:inline-block;text-decoration:none}.admin__field-tooltip .admin__field-tooltip-action:before{-webkit-font-smoothing:antialiased;font-size:2.2rem;line-height:1;color:#514943;content:'\e633';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.admin__field-tooltip .admin__control-text:focus+.admin__field-tooltip-content,.admin__field-tooltip:hover .admin__field-tooltip-content{display:block}.admin__field-tooltip .admin__field-tooltip-content{bottom:3.8rem;display:none;right:-2.3rem}.admin__field-tooltip .admin__field-tooltip-content:after,.admin__field-tooltip .admin__field-tooltip-content:before{border:1.6rem solid transparent;height:0;width:0;border-top-color:#afadac;content:'';display:block;position:absolute;right:2rem;top:100%;z-index:3}.admin__field-tooltip .admin__field-tooltip-content:after{border-top-color:#fffbbb;margin-top:-1px;z-index:4}.abs-admin__field-tooltip-content,.admin__field-tooltip .admin__field-tooltip-content{box-shadow:0 2px 8px 0 rgba(0,0,0,.3);background:#fffbbb;border:1px solid #afadac;border-radius:1px;padding:1.5rem 2.5rem;position:absolute;width:32rem;z-index:1}.admin__field-fallback-reset{font-size:1.25rem;white-space:nowrap;width:30px}.admin__field-fallback-reset>span{margin-left:.5rem;position:relative}.admin__field-fallback-reset:active{-ms-transform:scale(0.98);transform:scale(0.98)}.admin__field-fallback-reset:before{transition:color .1s linear;content:'\e642';font-size:1.3rem;margin-left:.5rem}.admin__field-fallback-reset:hover{cursor:pointer;text-decoration:none}.admin__field-fallback-reset:focus{background:0 0}.abs-field-size-x-small,.abs-field-sizes.admin__field-x-small>.admin__field-control,.admin__field.admin__field-x-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-x-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-x-small>.admin__field-control{width:8rem}.abs-field-size-small,.abs-field-sizes.admin__field-small>.admin__field-control,.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control,.admin__field.admin__field-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-small>.admin__field-control{width:15rem}.abs-field-size-medium,.abs-field-sizes.admin__field-medium>.admin__field-control,.admin__field.admin__field-medium>.admin__field-control,.admin__fieldset>.admin__field.admin__field-medium>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-medium>.admin__field-control{width:34rem}.abs-field-size-large,.abs-field-sizes.admin__field-large>.admin__field-control,.admin__field.admin__field-large>.admin__field-control,.admin__fieldset>.admin__field.admin__field-large>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-large>.admin__field-control{width:64rem}.abs-field-no-label,.admin__field-group-additional,.admin__field-no-label,.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-control{margin-left:calc((100%) * .25 + 30px)}.admin__fieldset{border:0;margin:0;min-width:0;padding:0}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title{padding-left:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title strong{font-size:1.7rem;font-weight:600}.admin__fieldset .fieldset-wrapper.admin__fieldset-section .admin__fieldset-wrapper-content>.admin__fieldset{padding-top:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section:last-child .admin__fieldset-wrapper-content>.admin__fieldset{padding-bottom:0}.admin__fieldset>.admin__field{border:0;margin:0 0 0 -30px;padding:0}.admin__fieldset>.admin__field:after{clear:both;content:'';display:table}.admin__fieldset>.admin__field>.admin__field-control{width:calc((100%) * .5 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-label{display:none}.admin__fieldset>.admin__field+.admin__field._empty._no-header{margin-top:-3rem}.admin__fieldset-product-websites{position:relative;z-index:300}.admin__fieldset-note{margin-bottom:2rem}.admin__form-field{border:0;margin:0;padding:0}.admin__field-control .admin__control-text,.admin__field-control .admin__control-textarea,.admin__form-field-control .admin__control-text,.admin__form-field-control .admin__control-textarea{width:100%}.admin__field-label{color:#303030;cursor:pointer;margin:0;text-align:right}.admin__field-label+br{display:none}.admin__field:not(.admin__field-option)>.admin__field-label{font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:3.2rem;padding:0;white-space:nowrap}.admin__field:not(.admin__field-option)>.admin__field-label:before{opacity:0;visibility:hidden;content:'.';margin-left:-7px;overflow:hidden}.admin__field:not(.admin__field-option)>.admin__field-label span{display:inline-block;line-height:1.2;vertical-align:middle;white-space:normal}.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]{position:relative}._required>.admin__field-label>span:after,.required>.admin__field-label>span:after{color:#eb5202;content:'*';display:inline-block;font-size:1.6rem;font-weight:500;line-height:1;margin-left:10px;margin-top:.2rem;position:absolute;z-index:1}._disabled>.admin__field-label{color:#999;cursor:default}.admin__field{margin-bottom:0}.admin__field+.admin__field{margin-top:1.5rem}.admin__field:not(.admin__field-option)~.admin__field-option{margin-top:.5rem}.admin__field.admin__field-option~.admin__field-option{margin-top:.9rem}.admin__field~.admin__field-option:last-child{margin-bottom:.8rem}.admin__fieldset>.admin__field{margin-bottom:3rem;position:relative}.admin__field legend.admin__field-label{opacity:0}.admin__field[data-config-scope]:before{color:gray;content:attr(data-config-scope);display:inline-block;font-size:1.2rem;left:calc((100%) * .75 - 30px);line-height:3.2rem;margin-left:60px;position:absolute;width:calc((100%) * .25 - 30px)}.admin__field-control .admin__field[data-config-scope]:nth-child(n+2):before{content:''}.admin__field._error .admin__field-control [class*=admin__addon-]:before,.admin__field._error .admin__field-control [class*=admin__control-] [class*=admin__addon-]:before,.admin__field._error .admin__field-control>[class*=admin__control-]{border-color:#e22626}.admin__field._disabled,.admin__field._disabled:hover{box-shadow:inherit;cursor:inherit;opacity:1;outline:inherit}.admin__field._hidden{display:none}.admin__field-control+.admin__field-control{margin-top:1.5rem}.admin__field-control._with-tooltip>.admin__control-addon,.admin__field-control._with-tooltip>.admin__control-select,.admin__field-control._with-tooltip>.admin__control-text,.admin__field-control._with-tooltip>.admin__control-textarea,.admin__field-control._with-tooltip>.admin__field-option{max-width:calc(100% - 45px - 4px)}.admin__field-control._with-tooltip .admin__field-tooltip{width:auto}.admin__field-control._with-tooltip .admin__field-option{display:inline-block}.admin__field-control._with-reset>.admin__control-addon,.admin__field-control._with-reset>.admin__control-text,.admin__field-control._with-reset>.admin__control-textarea{width:calc(100% - 30px - .5rem - 4px)}.admin__field-control._with-reset .admin__field-fallback-reset{margin-left:.5rem;margin-top:1rem;vertical-align:top}.admin__field-control._with-reset._with-tooltip>.admin__control-addon,.admin__field-control._with-reset._with-tooltip>.admin__control-text,.admin__field-control._with-reset._with-tooltip>.admin__control-textarea{width:calc(100% - 30px - .5rem - 45px - 8px)}.admin__fieldset>.admin__field-collapsible{margin-bottom:0}.admin__fieldset>.admin__field-collapsible .admin__field-control{border-top:1px solid #ccc;display:block;font-size:1.7rem;font-weight:700;padding:1.7rem 0;width:calc(97%)}.admin__fieldset>.admin__field-collapsible .admin__field-option{padding-top:0}.admin__field-collapsible+div{margin-top:2.5rem}.admin__field-collapsible .admin__control-radio+label:before{height:1.8rem;width:1.8rem}.admin__field-collapsible .admin__control-radio:checked+label:after{left:4px;top:5px}.admin__field-error{background:#fffbbb;border:1px solid #ee7d7d;box-sizing:border-box;color:#555;display:block;font-size:1.2rem;font-weight:400;line-height:1.2;margin:.2rem 0 0;padding:.8rem 1rem .9rem}.admin__field-note{color:#303030;font-size:1.2rem;margin:10px 0 0;padding:0}.admin__additional-info{padding-top:1rem}.admin__field-option{padding-top:.7rem}.admin__field-option .admin__field-label{text-align:left}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2),.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1){display:inline-block}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option{display:inline-block;margin-left:41px;margin-top:0}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option:before,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option:before{background:#cacaca;content:'';display:inline-block;height:20px;margin-left:-20px;position:absolute;width:1px}.admin__field-value{display:inline-block;padding-top:.7rem}.admin__field-service{padding-top:1rem}.admin__control-fields>.admin__field:first-child,[class*=admin__control-grouped]>.admin__field:first-child{position:static}.admin__control-fields>.admin__field:first-child>.admin__field-label,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px;background:#fff;cursor:pointer;left:0;position:absolute;top:0}.admin__control-fields>.admin__field:first-child>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label span:before{display:block}.admin__control-fields>.admin__field._disabled>.admin__field-label,[class*=admin__control-grouped]>.admin__field._disabled>.admin__field-label{cursor:default}.admin__control-fields>.admin__field>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field>.admin__field-label span:before{display:none}.admin__control-fields .admin__field-label~.admin__field-control{width:100%}.admin__control-fields .admin__field-option{padding-top:0}[class*=admin__control-grouped]{box-sizing:border-box;display:table;width:100%}[class*=admin__control-grouped]>.admin__field{display:table-cell;vertical-align:top}[class*=admin__control-grouped]>.admin__field>.admin__field-control{float:none;width:100%}[class*=admin__control-grouped]>.admin__field.admin__field-default,[class*=admin__control-grouped]>.admin__field.admin__field-large,[class*=admin__control-grouped]>.admin__field.admin__field-medium,[class*=admin__control-grouped]>.admin__field.admin__field-small,[class*=admin__control-grouped]>.admin__field.admin__field-x-small{width:1px}[class*=admin__control-grouped]>.admin__field.admin__field-default+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-large+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-medium+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-small+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-x-small+.admin__field:last-child{width:auto}[class*=admin__control-grouped]>.admin__field:nth-child(n+2){padding-left:20px}.admin__control-group-equal{table-layout:fixed}.admin__control-group-equal>.admin__field{width:50%}.admin__field-control-group{margin-top:.8rem}.admin__field-control-group>.admin__field{padding:0}.admin__control-grouped-date>.admin__field-date{white-space:nowrap;width:1px}.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control{float:left;position:relative}.admin__control-grouped-date>.admin__field-date+.admin__field:last-child{width:auto}.admin__control-grouped-date>.admin__field-date+.admin__field-date>.admin__field-label{float:left;padding-right:20px}.admin__control-grouped-date .ui-datepicker-trigger{left:100%;top:0}.admin__field-group-columns.admin__field-control.admin__control-grouped{width:calc((100%) * 1 - 30px);float:left;margin-left:30px}.admin__field-group-columns>.admin__field:first-child>.admin__field-label{float:none;margin:0;opacity:1;position:static;text-align:left}.admin__field-group-columns .admin__control-select{width:100%}.admin__field-group-additional{clear:both}.admin__field-group-additional .action-advanced{margin-top:1rem}.admin__field-group-additional .action-secondary{width:100%}.admin__field-group-show-label{white-space:nowrap}.admin__field-group-show-label>.admin__field-control,.admin__field-group-show-label>.admin__field-label{display:inline-block;vertical-align:top}.admin__field-group-show-label>.admin__field-label{margin-right:20px}.admin__field-complex{margin:1rem 0 3rem;padding-left:1rem}.admin__field:not(._hidden)+.admin__field-complex{margin-top:3rem}.admin__field-complex .admin__field-complex-title{clear:both;color:#303030;font-size:1.7rem;font-weight:600;letter-spacing:.025em;margin-bottom:1rem}.admin__field-complex .admin__field-complex-elements{float:right;max-width:40%}.admin__field-complex .admin__field-complex-elements button{margin-left:1rem}.admin__field-complex .admin__field-complex-content{max-width:60%;overflow:hidden}.admin__field-complex .admin__field-complex-text{margin-left:-1rem}.admin__field-complex+.admin__field._empty._no-header{margin-top:-3rem}.admin__legend{float:left;position:static;width:100%}.admin__legend+br{clear:left;display:block;height:0;overflow:hidden}.message{margin-bottom:3rem}.message-icon-top:before{margin-top:0;top:1.8rem}.nav{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;display:none;margin-bottom:3rem;padding:2.2rem 1.5rem 0 0}.nav .btn-group,.nav-bar-outer-actions{float:right;margin-bottom:1.7rem}.nav .btn-group .btn-wrap,.nav-bar-outer-actions .btn-wrap{float:right;margin-left:.5rem;margin-right:.5rem}.nav .btn-group .btn-wrap .btn,.nav-bar-outer-actions .btn-wrap .btn{padding-left:.5rem;padding-right:.5rem}.nav-bar-outer-actions{margin-top:-10.6rem;padding-right:1.5rem}.btn-wrap-try-again{width:9.5rem}.btn-wrap-next,.btn-wrap-prev{width:8.5rem}.nav-bar{counter-reset:i;float:left;margin:0 1rem 1.7rem 0;padding:0;position:relative;white-space:nowrap}.nav-bar:before{background-color:#d4d4d4;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#d1d1d1 0,#d4d4d4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d1d1d1', endColorstr='#d4d4d4', GradientType=0);border-bottom:1px solid #d9d9d9;border-top:1px solid #bfbfbf;content:'';height:1rem;left:5.15rem;position:absolute;right:5.15rem;top:.7rem}.nav-bar>li{display:inline-block;font-size:0;position:relative;vertical-align:top;width:10.3rem}.nav-bar>li:first-child:after{display:none}.nav-bar>li:after{background-color:#514943;content:'';height:.5rem;left:calc(-50% + .25rem);position:absolute;right:calc(50% + .7rem);top:.9rem}.nav-bar>li.disabled:before,.nav-bar>li.ui-state-disabled:before{bottom:0;content:'';left:0;position:absolute;right:0;top:0;z-index:1}.nav-bar>li.active~li:after,.nav-bar>li.ui-state-active~li:after{display:none}.nav-bar>li.active~li a:after,.nav-bar>li.ui-state-active~li a:after{background-color:transparent;border-color:transparent;color:#a6a6a6}.nav-bar>li.active a,.nav-bar>li.ui-state-active a{color:#000}.nav-bar>li.active a:hover,.nav-bar>li.ui-state-active a:hover{cursor:default}.nav-bar>li.active a:after,.nav-bar>li.ui-state-active a:after{background-color:#fff;content:''}.nav-bar a{color:#514943;display:block;font-size:1.2rem;font-weight:600;line-height:1.2;overflow:hidden;padding:3rem .5em 0;position:relative;text-align:center;text-overflow:ellipsis}.nav-bar a:hover{text-decoration:none}.nav-bar a:after{background-color:#514943;border:.4rem solid #514943;border-radius:100%;color:#fff;content:counter(i);counter-increment:i;height:1.5rem;left:50%;line-height:.6;margin-left:-.8rem;position:absolute;right:auto;text-align:center;top:.4rem;width:1.5rem}.nav-bar a:before{background-color:#d6d6d6;border:1px solid transparent;border-bottom-color:#d9d9d9;border-radius:100%;border-top-color:#bfbfbf;content:'';height:2.3rem;left:50%;line-height:1;margin-left:-1.2rem;position:absolute;top:0;width:2.3rem}.tooltip{display:block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.19rem;font-weight:400;line-height:1.4;opacity:0;position:absolute;visibility:visible;z-index:10}.tooltip.in{opacity:.9}.tooltip.top{margin-top:-4px;padding:8px 0}.tooltip.right{margin-left:4px;padding:0 8px}.tooltip.bottom{margin-top:4px;padding:8px 0}.tooltip.left{margin-left:-4px;padding:0 8px}.tooltip p:last-child{margin-bottom:0}.tooltip-inner{background-color:#fff;border:1px solid #adadad;border-radius:0;box-shadow:1px 1px 1px #ccc;color:#41362f;max-width:31rem;padding:.5em 1em;text-decoration:none}.tooltip-arrow,.tooltip-arrow:after{border:solid transparent;height:0;position:absolute;width:0}.tooltip-arrow:after{content:'';position:absolute}.tooltip.top .tooltip-arrow,.tooltip.top .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:50%;margin-left:-8px}.tooltip.top-left .tooltip-arrow,.tooltip.top-left .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;margin-bottom:-8px;right:8px}.tooltip.top-right .tooltip-arrow,.tooltip.top-right .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:8px;margin-bottom:-8px}.tooltip.right .tooltip-arrow,.tooltip.right .tooltip-arrow:after{border-right-color:#949494;border-width:8px 8px 8px 0;left:1px;margin-top:-8px;top:50%}.tooltip.right .tooltip-arrow:after{border-right-color:#fff;border-width:6px 7px 6px 0;margin-left:0;margin-top:-6px}.tooltip.left .tooltip-arrow,.tooltip.left .tooltip-arrow:after{border-left-color:#949494;border-width:8px 0 8px 8px;margin-top:-8px;right:0;top:50%}.tooltip.bottom .tooltip-arrow,.tooltip.bottom .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:50%;margin-left:-8px;top:0}.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;margin-top:-8px;right:8px;top:0}.tooltip.bottom-right .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:8px;margin-top:-8px;top:0}.password-strength{display:block;margin:0 -.3rem 1em;white-space:nowrap}.password-strength.password-strength-too-short .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child+.password-strength-item{background-color:#e22626}.password-strength.password-strength-fair .password-strength-item:first-child,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item+.password-strength-item{background-color:#ef672f}.password-strength.password-strength-good .password-strength-item:first-child,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item+.password-strength-item,.password-strength.password-strength-strong .password-strength-item{background-color:#79a22e}.password-strength .password-strength-item{background-color:#ccc;display:inline-block;font-size:0;height:1.4rem;margin-right:.3rem;width:calc(20% - .6rem)}@keyframes progress-bar-stripes{from{background-position:4rem 0}to{background-position:0 0}}.progress{background-color:#fafafa;border:1px solid #ccc;clear:left;height:3rem;margin-bottom:3rem;overflow:hidden}.progress-bar{background-color:#79a22e;color:#fff;float:left;font-size:1.19rem;height:100%;line-height:3rem;text-align:center;transition:width .6s ease;width:0}.progress-bar.active{animation:progress-bar-stripes 2s linear infinite}.progress-bar-text-description{margin-bottom:1.6rem}.progress-bar-text-progress{text-align:right}.page-columns .page-inner-sidebar{margin:0 0 3rem}.page-header{margin-bottom:2.7rem;padding-bottom:2rem;position:relative}.page-header:before{border-bottom:1px solid #e3e3e3;bottom:0;content:'';display:block;height:1px;left:3rem;position:absolute;right:3rem}.container .page-header:before{content:normal}.page-header .message{margin-bottom:1.8rem}.page-header .message+.message{margin-top:-1.5rem}.page-header .admin__action-dropdown,.page-header .search-global-input{transition:none}.container .page-header{margin-bottom:0}.page-title-wrapper{margin-top:1.1rem}.container .page-title-wrapper{background:url(../../pub/images/logo.svg) no-repeat;min-height:41px;padding:4px 0 0 45px}.admin__menu .level-0:first-child>a{margin-top:1.6rem}.admin__menu .level-0:first-child>a:after{top:-1.6rem}.admin__menu .level-0:first-child._active>a:after{display:block}.admin__menu .level-0>a{padding-bottom:1.3rem;padding-top:1.3rem}.admin__menu .level-0>a:before{margin-bottom:.7rem}.admin__menu .item-home>a:before{content:'\e611';font-size:2.3rem;padding-top:-.1rem}.admin__menu .item-component>a:before{content:'\e612'}.admin__menu .item-extension>a:before{content:'\e647'}.admin__menu .item-upgrade>a:before{content:'\e614'}.admin__menu .item-system-config>a:before{content:'\e610'}.admin__menu .item-tools>a:before{content:'\e613'}.modal-sub-title{font-size:1.7rem;font-weight:600}.modal-connect-signin .modal-inner-wrap{max-width:80rem}@keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}.ngdialog{-webkit-overflow-scrolling:touch;bottom:0;box-sizing:border-box;left:0;overflow:auto;position:fixed;right:0;top:0;z-index:999}.ngdialog *,.ngdialog:after,.ngdialog:before{box-sizing:inherit}.ngdialog.ngdialog-disabled-animation *{animation:none!important}.ngdialog.ngdialog-closing .ngdialog-content,.ngdialog.ngdialog-closing .ngdialog-overlay{-webkit-animation:ngdialog-fadeout .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadeout .5s}.ngdialog-overlay{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s;background:rgba(0,0,0,.4);bottom:0;left:0;position:fixed;right:0;top:0}.ngdialog-content{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s}body.ngdialog-open{overflow:hidden}.component-indicator{border-radius:50%;cursor:help;display:inline-block;height:16px;text-align:center;vertical-align:middle;width:16px}.component-indicator::after,.component-indicator::before{background:#fff;display:block;opacity:0;position:absolute;transition:opacity .2s linear .1s;visibility:hidden}.component-indicator::before{border:1px solid #adadad;border-radius:1px;box-shadow:0 0 2px rgba(0,0,0,.4);content:attr(data-label);font-size:1.2rem;margin:30px 0 0 -10px;min-width:50px;padding:4px 5px}.component-indicator::after{border-color:#999;border-style:solid;border-width:1px 0 0 1px;box-shadow:-1px -1px 1px rgba(0,0,0,.1);content:'';height:10px;margin:9px 0 0 5px;-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.component-indicator:hover::after,.component-indicator:hover::before{opacity:1;transition:opacity .2s linear;visibility:visible}.component-indicator span{display:block;height:16px;overflow:hidden;width:16px}.component-indicator span:before{content:'';display:block;font-family:Icons;font-size:16px;height:100%;line-height:16px;width:100%}.component-indicator._on{background:#79a22e}.component-indicator._off{background:#e22626}.component-indicator._off span:before{background:#fff;height:4px;margin:8px auto 20px;width:12px}.component-indicator._info{background:0 0}.component-indicator._info span{width:21px}.component-indicator._info span:before{color:#008bdb;content:'\e648';font-family:Icons;font-size:16px}.component-indicator._tooltip{background:0 0;margin:0 0 8px 5px}.component-indicator._tooltip a{width:21px}.component-indicator._tooltip a:hover{text-decoration:none}.component-indicator._tooltip a:before{color:#514943;content:'\e633';font-family:Icons;font-size:16px}.col-manager-item-name .data-grid-data{padding-left:5px}.col-manager-item-name .ng-hide+.data-grid-data{padding-left:24px}.col-manager-item-name ._hide-dependencies,.col-manager-item-name ._show-dependencies{cursor:pointer;padding-left:24px;position:relative}.col-manager-item-name ._hide-dependencies:before,.col-manager-item-name ._show-dependencies:before{display:block;font-family:Icons;font-size:12px;left:0;position:absolute;top:1px}.col-manager-item-name ._show-dependencies:before{content:'\e62b'}.col-manager-item-name ._hide-dependencies:before{content:'\e628'}.col-manager-item-name ._no-dependencies{padding-left:24px}.product-modules-block{font-size:1.2rem;padding:15px 0 0}.col-manager-item-name .product-modules-block{padding-left:1rem}.product-modules-descriprion,.product-modules-title{font-weight:700;margin:0 0 7px}.product-modules-list{font-size:1.1rem;list-style:none;margin:0}.col-manager-item-name .product-modules-list{margin-left:15px}.col-manager-item-name .product-modules-list li{padding:0 0 0 15px;position:relative}.product-modules-list li{margin:0 0 .5rem}.product-modules-list .component-indicator{height:10px;left:0;position:absolute;top:3px;width:10px}.module-summary{white-space:nowrap}.module-summary-title{font-size:2.1rem;margin-right:1rem}.app-updater .nav{display:block;margin-bottom:3.1rem;margin-top:-2.8rem}.app-updater .nav-bar-outer-actions{margin-top:1rem;padding-right:0}.app-updater .nav-bar-outer-actions .btn-wrap-cancel{margin-right:2.6rem}.main{padding-bottom:2rem;padding-top:3rem}.menu-wrapper .logo-static{pointer-events:none}.header{display:none}.header .logo{float:left;height:4.1rem;width:3.5rem}.header-title{font-size:2.8rem;letter-spacing:.02em;line-height:1.4;margin:2.5rem 0 3.5rem 5rem}.page-title{margin-bottom:1rem}.page-sub-title{font-size:2rem}.accent-box{margin-bottom:2rem}.accent-box .btn-prime{margin-top:1.5rem}.spinner.side{float:left;font-size:2.4rem;margin-left:2rem;margin-top:-5px}.page-landing{margin:7.6% auto 0;max-width:44rem;text-align:center}.page-landing .logo{height:5.6rem;margin-bottom:2rem;width:19.2rem}.page-landing .text-version{margin-bottom:3rem}.page-landing .text-welcome{margin-bottom:6.5rem}.page-landing .text-terms{margin-bottom:2.5rem;text-align:center}.page-landing .btn-submit,.page-license .license-text{margin-bottom:2rem}.page-license .page-license-footer{text-align:right}.readiness-check-item{margin-bottom:4rem;min-height:2.5rem}.readiness-check-item .spinner{float:left;font-size:2.5rem;margin:-.4rem 0 0 1.7rem}.readiness-check-title{font-size:1.4rem;font-weight:700;margin-bottom:.1rem;margin-left:5.7rem}.readiness-check-content{margin-left:5.7rem;margin-right:22rem;position:relative}.readiness-check-content .readiness-check-title{margin-left:0}.readiness-check-content .list{margin-top:-.3rem}.readiness-check-side{left:100%;padding-left:2.4rem;position:absolute;top:0;width:22rem}.readiness-check-side .side-title{margin-bottom:0}.readiness-check-icon{float:left;margin-left:1.7rem;margin-top:.3rem}.extensions-information{margin-bottom:5rem}.extensions-information h3{font-size:1.4rem;margin-bottom:1.3rem}.extensions-information .message{margin-bottom:2.5rem}.extensions-information .message:before{margin-top:0;top:1.8rem}.extensions-information .extensions-container{padding:0 2rem}.extensions-information .list{margin-bottom:1rem}.extensions-information .list select{cursor:pointer}.extensions-information .list select:disabled{background:#ccc;cursor:default}.extensions-information .list .extension-delete{font-size:1.7rem;padding-top:0}.delete-modal-wrap{padding:0 4% 4rem}.delete-modal-wrap h3{font-size:3.4rem;display:inline-block;font-weight:300;margin:0 0 2rem;padding:.9rem 0 0;vertical-align:top}.delete-modal-wrap .actions{padding:3rem 0 0}.page-web-configuration .form-el-insider-wrap{width:auto}.page-web-configuration .form-el-insider{width:15.4rem}.page-web-configuration .form-el-insider-input .form-el-input{width:16.5rem}.customize-your-store .advanced-modules-count,.customize-your-store .advanced-modules-select{padding-left:1.5rem}.customize-your-store .customize-your-store-advanced{min-width:0}.customize-your-store .message-error:before{margin-top:0;top:1.8rem}.customize-your-store .message-error a{color:#333;text-decoration:underline}.customize-your-store .message-error .form-label:before{background:#fff}.customize-your-store .customize-database-clean p{margin-top:2.5rem}.content-install{margin-bottom:2rem}.console{border:1px solid #ccc;font-family:'Courier New',Courier,monospace;font-weight:300;height:20rem;margin:1rem 0 2rem;overflow-y:auto;padding:1.5rem 2rem 2rem;resize:vertical}.console .text-danger{color:#e22626}.console .text-success{color:#090}.console .hidden{display:none}.content-success .btn-prime{margin-top:1.5rem}.jumbo-title{font-size:3.6rem}.jumbo-title .jumbo-icon{font-size:3.8rem;margin-right:.25em;position:relative;top:.15em}.install-database-clean{margin-top:4rem}.install-database-clean .btn{margin-right:1rem}.page-sub-title{margin-bottom:2.1rem;margin-top:3rem}.multiselect-custom{max-width:71.1rem}.content-install{margin-top:3.7rem}.home-page-inner-wrap{margin:0 auto;max-width:91rem}.setup-home-title{margin-bottom:3.9rem;padding-top:1.8rem;text-align:center}.setup-home-item{background-color:#fafafa;border:1px solid #ccc;color:#333;display:block;margin-bottom:2rem;margin-left:1.3rem;margin-right:1.3rem;min-height:30rem;padding:2rem;text-align:center}.setup-home-item:hover{border-color:#8c8c8c;color:#333;text-decoration:none;transition:border-color .1s linear}.setup-home-item:active{-ms-transform:scale(0.99);transform:scale(0.99)}.setup-home-item:before{display:block;font-size:7rem;margin-bottom:3.3rem;margin-top:4rem}.setup-home-item-component:before,.setup-home-item-extension:before{content:'\e612'}.setup-home-item-module:before{content:'\e647'}.setup-home-item-upgrade:before{content:'\e614'}.setup-home-item-configuration:before{content:'\e610'}.setup-home-item-title{display:block;font-size:1.8rem;letter-spacing:.025em;margin-bottom:1rem}.setup-home-item-description{display:block}.extension-manager-wrap{border:1px solid #bbb;margin:0 0 4rem}.extension-manager-account{font-size:2.1rem;display:inline-block;font-weight:400}.extension-manager-title{font-size:3.2rem;background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;color:#41362f;font-weight:600;line-height:1.2;padding:2rem}.extension-manager-content{padding:2.5rem 2rem 2rem}.extension-manager-items{list-style:none;margin:0;text-align:center}.extension-manager-items .btn{border:1px solid #adadad;display:block;margin:1rem auto 0}.extension-manager-items .item-title{font-size:2.1rem;display:inline-block;text-align:left}.extension-manager-items .item-number{font-size:4.1rem;display:inline-block;line-height:.8;margin:0 5px 1.5rem 0;vertical-align:top}.extension-manager-items .item-date{font-size:2.6rem;margin-top:1px}.extension-manager-items .item-date-title{font-size:1.5rem}.extension-manager-items .item-install{margin:0 0 2rem}.sync-login-wrap{padding:0 10% 4rem}.sync-login-wrap .legend{font-size:2.6rem;color:#eb5202;float:left;font-weight:300;line-height:1.2;margin:-1rem 0 2.5rem;position:static;width:100%}.sync-login-wrap .legend._hidden{display:none}.sync-login-wrap .login-header{font-size:3.4rem;font-weight:300;margin:0 0 2rem}.sync-login-wrap .login-header span{display:inline-block;padding:.9rem 0 0;vertical-align:top}.sync-login-wrap h4{font-size:1.4rem;margin:0 0 2rem}.sync-login-wrap .sync-login-steps{margin:0 0 2rem 1.5rem}.sync-login-wrap .sync-login-steps li{padding:0 0 0 1rem}.sync-login-wrap .form-row .form-label{display:inline-block}.sync-login-wrap .form-row .form-label.required{padding-left:1.5rem}.sync-login-wrap .form-row .form-label.required:after{left:0;position:absolute;right:auto}.sync-login-wrap .form-row{max-width:28rem}.sync-login-wrap .form-actions{display:table;margin-top:-1.3rem}.sync-login-wrap .form-actions .links{display:table-header-group}.sync-login-wrap .form-actions .actions{padding:3rem 0 0}@media all and (max-width:1047px){.admin__menu .submenu li{min-width:19.8rem}.nav{padding-bottom:5.38rem;padding-left:1.5rem;text-align:center}.nav-bar{display:inline-block;float:none;margin-right:0;vertical-align:top}.nav .btn-group,.nav-bar-outer-actions{display:inline-block;float:none;margin-top:-8.48rem;text-align:center;vertical-align:top;width:100%}.nav-bar-outer-actions{padding-right:0}.nav-bar-outer-actions .outer-actions-inner-wrap{display:inline-block}.app-updater .nav{padding-bottom:1.7rem}.app-updater .nav-bar-outer-actions{margin-top:2rem}}@media all and (min-width:768px){.page-layout-admin-2columns-left .page-columns{margin-left:-30px}.page-layout-admin-2columns-left .page-columns:after{clear:both;content:'';display:table}.page-layout-admin-2columns-left .page-columns .main-col{width:calc((100%) * .75 - 30px);float:right}.page-layout-admin-2columns-left .page-columns .side-col{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9{float:left}.col-m-12{width:100%}.col-m-11{width:91.66666667%}.col-m-10{width:83.33333333%}.col-m-9{width:75%}.col-m-8{width:66.66666667%}.col-m-7{width:58.33333333%}.col-m-6{width:50%}.col-m-5{width:41.66666667%}.col-m-4{width:33.33333333%}.col-m-3{width:25%}.col-m-2{width:16.66666667%}.col-m-1{width:8.33333333%}.col-m-pull-12{right:100%}.col-m-pull-11{right:91.66666667%}.col-m-pull-10{right:83.33333333%}.col-m-pull-9{right:75%}.col-m-pull-8{right:66.66666667%}.col-m-pull-7{right:58.33333333%}.col-m-pull-6{right:50%}.col-m-pull-5{right:41.66666667%}.col-m-pull-4{right:33.33333333%}.col-m-pull-3{right:25%}.col-m-pull-2{right:16.66666667%}.col-m-pull-1{right:8.33333333%}.col-m-pull-0{right:auto}.col-m-push-12{left:100%}.col-m-push-11{left:91.66666667%}.col-m-push-10{left:83.33333333%}.col-m-push-9{left:75%}.col-m-push-8{left:66.66666667%}.col-m-push-7{left:58.33333333%}.col-m-push-6{left:50%}.col-m-push-5{left:41.66666667%}.col-m-push-4{left:33.33333333%}.col-m-push-3{left:25%}.col-m-push-2{left:16.66666667%}.col-m-push-1{left:8.33333333%}.col-m-push-0{left:auto}.col-m-offset-12{margin-left:100%}.col-m-offset-11{margin-left:91.66666667%}.col-m-offset-10{margin-left:83.33333333%}.col-m-offset-9{margin-left:75%}.col-m-offset-8{margin-left:66.66666667%}.col-m-offset-7{margin-left:58.33333333%}.col-m-offset-6{margin-left:50%}.col-m-offset-5{margin-left:41.66666667%}.col-m-offset-4{margin-left:33.33333333%}.col-m-offset-3{margin-left:25%}.col-m-offset-2{margin-left:16.66666667%}.col-m-offset-1{margin-left:8.33333333%}.col-m-offset-0{margin-left:0}.page-columns{margin-left:-30px}.page-columns:after{clear:both;content:'';display:table}.page-columns .page-inner-content{width:calc((100%) * .75 - 30px);float:right}.page-columns .page-inner-sidebar{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}}@media all and (min-width:1048px){.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9{float:left}.col-l-12{width:100%}.col-l-11{width:91.66666667%}.col-l-10{width:83.33333333%}.col-l-9{width:75%}.col-l-8{width:66.66666667%}.col-l-7{width:58.33333333%}.col-l-6{width:50%}.col-l-5{width:41.66666667%}.col-l-4{width:33.33333333%}.col-l-3{width:25%}.col-l-2{width:16.66666667%}.col-l-1{width:8.33333333%}.col-l-pull-12{right:100%}.col-l-pull-11{right:91.66666667%}.col-l-pull-10{right:83.33333333%}.col-l-pull-9{right:75%}.col-l-pull-8{right:66.66666667%}.col-l-pull-7{right:58.33333333%}.col-l-pull-6{right:50%}.col-l-pull-5{right:41.66666667%}.col-l-pull-4{right:33.33333333%}.col-l-pull-3{right:25%}.col-l-pull-2{right:16.66666667%}.col-l-pull-1{right:8.33333333%}.col-l-pull-0{right:auto}.col-l-push-12{left:100%}.col-l-push-11{left:91.66666667%}.col-l-push-10{left:83.33333333%}.col-l-push-9{left:75%}.col-l-push-8{left:66.66666667%}.col-l-push-7{left:58.33333333%}.col-l-push-6{left:50%}.col-l-push-5{left:41.66666667%}.col-l-push-4{left:33.33333333%}.col-l-push-3{left:25%}.col-l-push-2{left:16.66666667%}.col-l-push-1{left:8.33333333%}.col-l-push-0{left:auto}.col-l-offset-12{margin-left:100%}.col-l-offset-11{margin-left:91.66666667%}.col-l-offset-10{margin-left:83.33333333%}.col-l-offset-9{margin-left:75%}.col-l-offset-8{margin-left:66.66666667%}.col-l-offset-7{margin-left:58.33333333%}.col-l-offset-6{margin-left:50%}.col-l-offset-5{margin-left:41.66666667%}.col-l-offset-4{margin-left:33.33333333%}.col-l-offset-3{margin-left:25%}.col-l-offset-2{margin-left:16.66666667%}.col-l-offset-1{margin-left:8.33333333%}.col-l-offset-0{margin-left:0}}@media all and (min-width:1440px){.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{float:left}.col-xl-12{width:100%}.col-xl-11{width:91.66666667%}.col-xl-10{width:83.33333333%}.col-xl-9{width:75%}.col-xl-8{width:66.66666667%}.col-xl-7{width:58.33333333%}.col-xl-6{width:50%}.col-xl-5{width:41.66666667%}.col-xl-4{width:33.33333333%}.col-xl-3{width:25%}.col-xl-2{width:16.66666667%}.col-xl-1{width:8.33333333%}.col-xl-pull-12{right:100%}.col-xl-pull-11{right:91.66666667%}.col-xl-pull-10{right:83.33333333%}.col-xl-pull-9{right:75%}.col-xl-pull-8{right:66.66666667%}.col-xl-pull-7{right:58.33333333%}.col-xl-pull-6{right:50%}.col-xl-pull-5{right:41.66666667%}.col-xl-pull-4{right:33.33333333%}.col-xl-pull-3{right:25%}.col-xl-pull-2{right:16.66666667%}.col-xl-pull-1{right:8.33333333%}.col-xl-pull-0{right:auto}.col-xl-push-12{left:100%}.col-xl-push-11{left:91.66666667%}.col-xl-push-10{left:83.33333333%}.col-xl-push-9{left:75%}.col-xl-push-8{left:66.66666667%}.col-xl-push-7{left:58.33333333%}.col-xl-push-6{left:50%}.col-xl-push-5{left:41.66666667%}.col-xl-push-4{left:33.33333333%}.col-xl-push-3{left:25%}.col-xl-push-2{left:16.66666667%}.col-xl-push-1{left:8.33333333%}.col-xl-push-0{left:auto}.col-xl-offset-12{margin-left:100%}.col-xl-offset-11{margin-left:91.66666667%}.col-xl-offset-10{margin-left:83.33333333%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-8{margin-left:66.66666667%}.col-xl-offset-7{margin-left:58.33333333%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-5{margin-left:41.66666667%}.col-xl-offset-4{margin-left:33.33333333%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-2{margin-left:16.66666667%}.col-xl-offset-1{margin-left:8.33333333%}.col-xl-offset-0{margin-left:0}}@media all and (max-width:767px){.abs-clearer-mobile:after,.nav-bar:after{clear:both;content:'';display:table}.list-definition>dt{float:none}.list-definition>dd{margin-left:0}.form-row .form-label{text-align:left}.form-row .form-label.required:after{position:static}.nav{padding-bottom:0;padding-left:0;padding-right:0}.nav-bar-outer-actions{margin-top:0}.nav-bar{display:block;margin-bottom:0;margin-left:auto;margin-right:auto;width:30.9rem}.nav-bar:before{display:none}.nav-bar>li{float:left;min-height:9rem}.nav-bar>li:after{display:none}.nav-bar>li:nth-child(4n){clear:both}.nav-bar a{line-height:1.4}.tooltip{display:none!important}.readiness-check-content{margin-right:2rem}.readiness-check-side{padding:2rem 0;position:static}.form-el-insider,.form-el-insider-wrap,.page-web-configuration .form-el-insider-input,.page-web-configuration .form-el-insider-input .form-el-input{display:block;width:100%}}@media all and (max-width:479px){.nav-bar{width:23.175rem}.nav-bar>li{width:7.725rem}.nav .btn-group .btn-wrap-try-again,.nav-bar-outer-actions .btn-wrap-try-again{clear:both;display:block;float:none;margin-left:auto;margin-right:auto;margin-top:1rem;padding-top:1rem}} \ No newline at end of file +.abs-action-delete,.abs-icon,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.validation-symbol:after{color:#e22626;content:'*';font-weight:400;margin-left:3px}.abs-modal-overlay,.modals-overlay{background:rgba(0,0,0,.35);bottom:0;left:0;position:fixed;right:0;top:0}.abs-action-delete>span,.abs-visually-hidden,.action-multicheck-wrap .action-multicheck-toggle>span,.admin__actions-switch-checkbox,.admin__control-fields .admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label)>.admin__field-label,.admin__field-tooltip .admin__field-tooltip-action span,.customize-your-store .customize-your-store-default .legend,.extensions-information .list .extension-delete>span,.form-el-checkbox,.form-el-radio,.selectmenu .action-delete>span,.selectmenu .action-edit>span,.selectmenu .action-save>span,.selectmenu-toggle span,.tooltip .help a span,.tooltip .help span span,[class*=admin__control-grouped]>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.abs-visually-hidden-reset,.admin__field-group-columns>.admin__field:nth-child(n+2):not(.admin__field-option):not(.admin__field-group-show-label):not(.admin__field-date)>.admin__field-label[class]{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.abs-clearfix:after,.abs-clearfix:before,.action-multicheck-wrap:after,.action-multicheck-wrap:before,.actions-split:after,.actions-split:before,.admin__control-table-pagination:after,.admin__control-table-pagination:before,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:before,.admin__data-grid-filters-footer:after,.admin__data-grid-filters-footer:before,.admin__data-grid-filters:after,.admin__data-grid-filters:before,.admin__data-grid-header-row:after,.admin__data-grid-header-row:before,.admin__field-complex:after,.admin__field-complex:before,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .magento-message .insert-title-inner:before,.modal-slide .main-col .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:before,.page-actions._fixed:after,.page-actions._fixed:before,.page-content:after,.page-content:before,.page-header-actions:after,.page-header-actions:before,.page-main-actions:not(._hidden):after,.page-main-actions:not(._hidden):before{content:'';display:table}.abs-clearfix:after,.action-multicheck-wrap:after,.actions-split:after,.admin__control-table-pagination:after,.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content:after,.admin__data-grid-filters-footer:after,.admin__data-grid-filters:after,.admin__data-grid-header-row:after,.admin__field-complex:after,.modal-slide .magento-message .insert-title-inner:after,.modal-slide .main-col .insert-title-inner:after,.page-actions._fixed:after,.page-content:after,.page-header-actions:after,.page-main-actions:not(._hidden):after{clear:both}.abs-list-reset-styles{margin:0;padding:0;list-style:none}.abs-draggable-handle,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle,.admin__control-table .draggable-handle,.data-grid .data-grid-draggable-row-cell .draggable-handle{cursor:-webkit-grab;cursor:move;font-size:0;margin-top:-4px;padding:0 1rem 0 0;vertical-align:middle;display:inline-block;text-decoration:none}.abs-draggable-handle:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:before,.admin__control-table .draggable-handle:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:before{-webkit-font-smoothing:antialiased;font-size:1.8rem;line-height:inherit;color:#9e9e9e;content:'\e617';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.abs-draggable-handle:hover:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .draggable-handle:hover:before,.admin__control-table .draggable-handle:hover:before,.data-grid .data-grid-draggable-row-cell .draggable-handle:hover:before{color:#858585}.abs-config-scope-label,.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]:before{bottom:-1.3rem;color:gray;content:attr(data-config-scope);font-size:1.1rem;font-weight:400;min-width:15rem;position:absolute;right:0;text-transform:lowercase}.abs-word-wrap,.admin__field:not(.admin__field-option)>.admin__field-label{overflow-wrap:break-word;word-wrap:break-word;-ms-word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;box-sizing:border-box}*,:after,:before{box-sizing:inherit}:focus{box-shadow:none;outline:0}._keyfocus :focus{box-shadow:0 0 0 1px #008bdb}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}embed,img,object,video{max-width:100%}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/light/opensans-300.eot);src:url(../fonts/opensans/light/opensans-300.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/light/opensans-300.woff2) format('woff2'),url(../fonts/opensans/light/opensans-300.woff) format('woff'),url(../fonts/opensans/light/opensans-300.ttf) format('truetype'),url('../fonts/opensans/light/opensans-300.svg#Open Sans') format('svg');font-weight:300;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/regular/opensans-400.eot);src:url(../fonts/opensans/regular/opensans-400.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/regular/opensans-400.woff2) format('woff2'),url(../fonts/opensans/regular/opensans-400.woff) format('woff'),url(../fonts/opensans/regular/opensans-400.ttf) format('truetype'),url('../fonts/opensans/regular/opensans-400.svg#Open Sans') format('svg');font-weight:400;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/semibold/opensans-600.eot);src:url(../fonts/opensans/semibold/opensans-600.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/semibold/opensans-600.woff2) format('woff2'),url(../fonts/opensans/semibold/opensans-600.woff) format('woff'),url(../fonts/opensans/semibold/opensans-600.ttf) format('truetype'),url('../fonts/opensans/semibold/opensans-600.svg#Open Sans') format('svg');font-weight:600;font-style:normal}@font-face{font-family:'Open Sans';src:url(../fonts/opensans/bold/opensans-700.eot);src:url(../fonts/opensans/bold/opensans-700.eot?#iefix) format('embedded-opentype'),url(../fonts/opensans/bold/opensans-700.woff2) format('woff2'),url(../fonts/opensans/bold/opensans-700.woff) format('woff'),url(../fonts/opensans/bold/opensans-700.ttf) format('truetype'),url('../fonts/opensans/bold/opensans-700.svg#Open Sans') format('svg');font-weight:700;font-style:normal}html{font-size:62.5%}body{color:#333;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.36;font-size:1.4rem}h1{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2.8rem}h2{margin:0 0 2rem;color:#41362f;font-weight:400;line-height:1.2;font-size:2rem}h3{margin:0 0 2rem;color:#41362f;font-weight:600;line-height:1.2;font-size:1.7rem}h4,h5,h6{font-weight:600;margin-top:0}p{margin:0 0 1em}small{font-size:1.2rem}a{color:#008bdb;text-decoration:none}a:hover{color:#0fa7ff;text-decoration:underline}dl,ol,ul{padding-left:0}nav ol,nav ul{list-style:none;margin:0;padding:0}html{height:100%}body{background-color:#fff;min-height:100%;min-width:102.4rem}.page-wrapper{background-color:#fff;display:inline-block;margin-left:-4px;vertical-align:top;width:calc(100% - 8.8rem)}.page-content{padding-bottom:3rem;padding-left:3rem;padding-right:3rem}.notices-wrapper{margin:0 3rem}.notices-wrapper .messages{margin-bottom:0}.row{margin-left:0;margin-right:0}.row:after{clear:both;content:'';display:table}.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9,.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{min-height:1px;padding-left:0;padding-right:0;position:relative}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}.row-gutter{margin-left:-1.5rem;margin-right:-1.5rem}.row-gutter>[class*=col-]{padding-left:1.5rem;padding-right:1.5rem}.abs-clearer:after,.extension-manager-content:after,.extension-manager-title:after,.form-row:after,.header:after,.nav:after,body:after{clear:both;content:'';display:table}.ng-cloak{display:none!important}.hide.hide{display:none}.show.show{display:block}.text-center{text-align:center}.text-right{text-align:right}@font-face{font-family:Icons;src:url(../fonts/icons/icons.eot);src:url(../fonts/icons/icons.eot?#iefix) format('embedded-opentype'),url(../fonts/icons/icons.woff2) format('woff2'),url(../fonts/icons/icons.woff) format('woff'),url(../fonts/icons/icons.ttf) format('truetype'),url(../fonts/icons/icons.svg#Icons) format('svg');font-weight:400;font-style:normal}[class*=icon-]{display:inline-block;line-height:1}.icon-failed:before,.icon-success:before,[class*=icon-]:after{font-family:Icons}.icon-success{color:#79a22e}.icon-success:before{content:'\e62d'}.icon-failed{color:#e22626}.icon-failed:before{content:'\e632'}.icon-success-thick:after{content:'\e62d'}.icon-collapse:after{content:'\e615'}.icon-failed-thick:after{content:'\e632'}.icon-expand:after{content:'\e616'}.icon-warning:after{content:'\e623'}.icon-failed-round,.icon-success-round{border-radius:100%;color:#fff;font-size:2.5rem;height:1em;position:relative;text-align:center;width:1em}.icon-failed-round:after,.icon-success-round:after{bottom:0;font-size:.5em;left:0;position:absolute;right:0;top:.45em}.icon-success-round{background-color:#79a22e}.icon-success-round:after{content:'\e62d'}.icon-failed-round{background-color:#e22626}.icon-failed-round:after{content:'\e632'}dl,ol,ul{margin-top:0}.list{padding-left:0}.list>li{display:block;margin-bottom:.75em;position:relative}.list>li>.icon-failed,.list>li>.icon-success{font-size:1.6em;left:-.1em;position:absolute;top:0}.list>li>.icon-success{color:#79a22e}.list>li>.icon-failed{color:#e22626}.list-item-failed,.list-item-icon,.list-item-success,.list-item-warning{padding-left:3.5rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{left:-.1em;position:absolute}.list-item-success:before{color:#79a22e}.list-item-failed:before{color:#e22626}.list-item-warning:before{color:#ef672f}.list-definition{margin:0 0 3rem;padding:0}.list-definition>dt{clear:left;float:left}.list-definition>dd{margin-bottom:1em;margin-left:20rem}.btn-wrap{margin:0 auto}.btn-wrap .btn{width:100%}.btn{background:#e3e3e3;border:none;color:#514943;display:inline-block;font-size:1.6rem;font-weight:600;padding:.45em .9em;text-align:center}.btn:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.btn:active{background-color:#d6d6d6}.btn.disabled,.btn[disabled]{cursor:default;opacity:.5;pointer-events:none}.ie9 .btn.disabled,.ie9 .btn[disabled]{background-color:#f0f0f0;opacity:1;text-shadow:none}.btn-large{padding:.75em 1.25em}.btn-medium{font-size:1.4rem;padding:.5em 1.5em .6em}.btn-link{background-color:transparent;border:none;color:#008bdb;font-family:1.6rem;font-size:1.5rem}.btn-link:active,.btn-link:focus,.btn-link:hover{background-color:transparent;color:#0fa7ff}.btn-prime{background-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.btn-prime:focus,.btn-prime:hover{background-color:#f65405;background-repeat:repeat-x;background-image:linear-gradient(to right,#e04f00 0,#f65405 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e04f00', endColorstr='#f65405', GradientType=1);color:#fff}.btn-prime:active{background-color:#e04f00;background-repeat:repeat-x;background-image:linear-gradient(to right,#f65405 0,#e04f00 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f65405', endColorstr='#e04f00', GradientType=1);color:#fff}.ie9 .btn-prime.disabled,.ie9 .btn-prime[disabled]{background-color:#fd6e23}.ie9 .btn-prime.disabled:active,.ie9 .btn-prime.disabled:hover,.ie9 .btn-prime[disabled]:active,.ie9 .btn-prime[disabled]:hover{background-color:#fd6e23;-webkit-filter:none;filter:none}.btn-secondary{background-color:#514943;color:#fff}.btn-secondary:hover{background-color:#5f564f;color:#fff}.btn-secondary:active,.btn-secondary:focus{background-color:#574e48;color:#fff}.ie9 .btn-secondary.disabled,.ie9 .btn-secondary[disabled]{background-color:#514943}.ie9 .btn-secondary.disabled:active,.ie9 .btn-secondary[disabled]:active{background-color:#514943;-webkit-filter:none;filter:none}[class*=btn-wrap-triangle]{overflow:hidden;position:relative}[class*=btn-wrap-triangle] .btn:after{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.btn-wrap-triangle-right{display:inline-block;padding-right:1.74rem;position:relative}.btn-wrap-triangle-right .btn{text-indent:.92rem}.btn-wrap-triangle-right .btn:after{border-color:transparent transparent transparent #e3e3e3;border-width:1.84rem 0 1.84rem 1.84rem;left:100%;margin-left:-1.74rem}.btn-wrap-triangle-right .btn:focus:after,.btn-wrap-triangle-right .btn:hover:after{border-left-color:#dbdbdb}.btn-wrap-triangle-right .btn:active:after{border-left-color:#d6d6d6}.btn-wrap-triangle-right .btn:not(.disabled):active,.btn-wrap-triangle-right .btn:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn.disabled:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:after{border-color:transparent transparent transparent #f0f0f0}.ie9 .btn-wrap-triangle-right .btn.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn.disabled:focus:after,.ie9 .btn-wrap-triangle-right .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:focus:after,.ie9 .btn-wrap-triangle-right .btn[disabled]:hover:after{border-left-color:#f0f0f0}.btn-wrap-triangle-right .btn-prime:after{border-color:transparent transparent transparent #eb5202}.btn-wrap-triangle-right .btn-prime:focus:after,.btn-wrap-triangle-right .btn-prime:hover:after{border-left-color:#f65405}.btn-wrap-triangle-right .btn-prime:active:after{border-left-color:#e04f00}.btn-wrap-triangle-right .btn-prime:not(.disabled):active,.btn-wrap-triangle-right .btn-prime:not([disabled]):active{left:1px}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:after{border-color:transparent transparent transparent #fd6e23}.ie9 .btn-wrap-triangle-right .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-right .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-right .btn-prime[disabled]:hover:after{border-left-color:#fd6e23}.btn-wrap-triangle-left{display:inline-block;padding-left:1.74rem}.btn-wrap-triangle-left .btn{text-indent:-.92rem}.btn-wrap-triangle-left .btn:after{border-color:transparent #e3e3e3 transparent transparent;border-width:1.84rem 1.84rem 1.84rem 0;margin-right:-1.74rem;right:100%}.btn-wrap-triangle-left .btn:focus:after,.btn-wrap-triangle-left .btn:hover:after{border-right-color:#dbdbdb}.btn-wrap-triangle-left .btn:active:after{border-right-color:#d6d6d6}.btn-wrap-triangle-left .btn:not(.disabled):active,.btn-wrap-triangle-left .btn:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn.disabled:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:after{border-color:transparent #f0f0f0 transparent transparent}.ie9 .btn-wrap-triangle-left .btn.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn[disabled]:hover:after{border-right-color:#f0f0f0}.btn-wrap-triangle-left .btn-prime:after{border-color:transparent #eb5202 transparent transparent}.btn-wrap-triangle-left .btn-prime:focus:after,.btn-wrap-triangle-left .btn-prime:hover:after{border-right-color:#e04f00}.btn-wrap-triangle-left .btn-prime:active:after{border-right-color:#f65405}.btn-wrap-triangle-left .btn-prime:not(.disabled):active,.btn-wrap-triangle-left .btn-prime:not([disabled]):active{right:1px}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:after{border-color:transparent #fd6e23 transparent transparent}.ie9 .btn-wrap-triangle-left .btn-prime.disabled:active:after,.ie9 .btn-wrap-triangle-left .btn-prime.disabled:hover:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:active:after,.ie9 .btn-wrap-triangle-left .btn-prime[disabled]:hover:after{border-right-color:#fd6e23}.btn-expand{background-color:transparent;border:none;color:#303030;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700;padding:0;position:relative}.btn-expand.expanded:after{border-color:transparent transparent #303030;border-width:0 .285em .36em}.btn-expand.expanded:hover:after{border-color:transparent transparent #3d3d3d}.btn-expand:hover{background-color:transparent;border:none;color:#3d3d3d}.btn-expand:hover:after{border-color:#3d3d3d transparent transparent}.btn-expand:after{border-color:#303030 transparent transparent;border-style:solid;border-width:.36em .285em 0;content:'';height:0;left:100%;margin-left:.5em;margin-top:-.18em;position:absolute;top:50%;width:0}[class*=col-] .form-el-input,[class*=col-] .form-el-select{width:100%}.form-fieldset{border:none;margin:0 0 1em;padding:0}.form-row{margin-bottom:2.2rem}.form-row .form-row{margin-bottom:.4rem}.form-row .form-label{display:block;font-weight:600;padding:.6rem 2.1em 0 0;text-align:right}.form-row .form-label.required{position:relative}.form-row .form-label.required:after{color:#eb5202;content:'*';font-size:1.15em;position:absolute;right:.7em;top:.5em}.form-row .form-el-checkbox+.form-label:before,.form-row .form-el-radio+.form-label:before{top:.7rem}.form-row .form-el-checkbox+.form-label:after,.form-row .form-el-radio+.form-label:after{top:1.1rem}.form-row.form-row-text{padding-top:.6rem}.form-row.form-row-text .action-sign-out{font-size:1.2rem;margin-left:1rem}.form-note{font-size:1.2rem;font-weight:600;margin-top:1rem}.form-el-dummy{display:none}.fieldset{border:0;margin:0;min-width:0;padding:0}input:not([disabled]):focus,textarea:not([disabled]):focus{box-shadow:none}.form-el-input{border:1px solid #adadad;color:#303030;padding:.35em .55em .5em}.form-el-input:hover{border-color:#949494}.form-el-input:focus{border-color:#008bdb}.form-el-input:required{box-shadow:none}.form-label{margin-bottom:.5em}[class*=form-label][for]{cursor:pointer}.form-el-insider-wrap{display:table;width:100%}.form-el-insider-input{display:table-cell;width:100%}.form-el-insider{border-radius:2px;display:table-cell;padding:.43em .55em .5em 0;vertical-align:top}.form-legend,.form-legend-expand,.form-legend-light{display:block;margin:0}.form-legend,.form-legend-expand{font-size:1.25em;font-weight:600;margin-bottom:2.5em;padding-top:1.5em}.form-legend{border-top:1px solid #ccc;width:100%}.form-legend-light{font-size:1em;margin-bottom:1.5em}.form-legend-expand{cursor:pointer;transition:opacity .2s linear}.form-legend-expand:hover{opacity:.85}.form-legend-expand.expanded:after{content:'\e615'}.form-legend-expand:after{content:'\e616';font-family:Icons;font-size:1.15em;font-weight:400;margin-left:.5em;vertical-align:sub}.form-el-checkbox.disabled+.form-label,.form-el-checkbox.disabled+.form-label:before,.form-el-checkbox[disabled]+.form-label,.form-el-checkbox[disabled]+.form-label:before,.form-el-radio.disabled+.form-label,.form-el-radio.disabled+.form-label:before,.form-el-radio[disabled]+.form-label,.form-el-radio[disabled]+.form-label:before{cursor:default;opacity:.5;pointer-events:none}.form-el-checkbox:not(.disabled)+.form-label:hover:before,.form-el-checkbox:not([disabled])+.form-label:hover:before,.form-el-radio:not(.disabled)+.form-label:hover:before,.form-el-radio:not([disabled])+.form-label:hover:before{border-color:#514943}.form-el-checkbox+.form-label,.form-el-radio+.form-label{font-weight:400;padding-left:2em;padding-right:0;position:relative;text-align:left;transition:border-color .1s linear}.form-el-checkbox+.form-label:before,.form-el-radio+.form-label:before{border:1px solid;content:'';left:0;position:absolute;top:.1rem;transition:border-color .1s linear}.form-el-checkbox+.form-label:before{background-color:#fff;border-color:#adadad;border-radius:2px;font-size:1.2rem;height:1.6rem;line-height:1.2;width:1.6rem}.form-el-checkbox:checked+.form-label::before{content:'\e62d';font-family:Icons}.form-el-radio+.form-label:before{background-color:#fff;border:1px solid #adadad;border-radius:100%;height:1.8rem;width:1.8rem}.form-el-radio+.form-label:after{background:0 0;border:.5rem solid transparent;border-radius:100%;content:'';height:0;left:.4rem;position:absolute;top:.5rem;transition:background .3s linear;width:0}.form-el-radio:checked+.form-label{cursor:default}.form-el-radio:checked+.form-label:after{border-color:#514943}.form-select-label{border:1px solid #adadad;color:#303030;cursor:pointer;display:block;overflow:hidden;position:relative;z-index:0}.form-select-label:hover,.form-select-label:hover:after{border-color:#949494}.form-select-label:active,.form-select-label:active:after,.form-select-label:focus,.form-select-label:focus:after{border-color:#008bdb}.form-select-label:after{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:2.36em;z-index:-2}.ie9 .form-select-label:after{display:none}.form-select-label:before{border-color:#303030 transparent transparent;border-style:solid;border-width:5px 4px 0;content:'';height:0;margin-right:-4px;margin-top:-2.5px;position:absolute;right:1.18em;top:50%;width:0;z-index:-1}.ie9 .form-select-label:before{display:none}.form-select-label .form-el-select{background:0 0;border:none;border-radius:0;content:'';display:block;margin:0;padding:.35em calc(2.36em + 10%) .5em .55em;width:110%}.ie9 .form-select-label .form-el-select{padding-right:.55em;width:100%}.form-select-label .form-el-select::-ms-expand{display:none}.form-el-select{background:#fff;border:1px solid #adadad;border-radius:2px;color:#303030;display:block;padding:.35em .55em}.multiselect-custom{border:1px solid #adadad;height:45.2rem;margin:0 0 1.5rem;overflow:auto;position:relative}.multiselect-custom ul{margin:0;padding:0;list-style:none;min-width:29rem}.multiselect-custom .item{padding:1rem 1.4rem}.multiselect-custom .selected{background-color:#e0f6fe}.multiselect-custom .form-label{margin-bottom:0}[class*=form-el-].invalid{border-color:#e22626}[class*=form-el-].invalid+.error-container{display:block}.error-container{background-color:#fffbbb;border:1px solid #ee7d7d;color:#514943;display:none;font-size:1.19rem;margin-top:.2rem;padding:.8rem 1rem .9rem}.check-result-message{margin-left:.5em;min-height:3.68rem;-ms-align-items:center;-ms-flex-align:center;align-items:center;display:-ms-flexbox;display:flex}.check-result-text{margin-left:.5em}body:not([class]){min-width:0}.container{display:block;margin:0 auto 4rem;max-width:100rem;padding:0}.abs-action-delete,.action-close:before,.action-next:before,.action-previous:before,.admin-user .admin__action-dropdown:before,.admin__action-multiselect-dropdown:before,.admin__action-multiselect-search-label:before,.admin__control-checkbox+label:before,.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before,.admin__control-table .action-delete:before,.admin__current-filters-list .action-remove:before,.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before,.admin__data-grid-action-bookmarks .admin__action-dropdown:before,.admin__data-grid-action-columns .admin__action-dropdown:before,.admin__data-grid-action-export .admin__action-dropdown:before,.admin__field-fallback-reset:before,.admin__menu .level-0>a:before,.admin__page-nav-item-message .admin__page-nav-item-message-icon,.admin__page-nav-title._collapsible:after,.data-grid-filters-action-wrap .action-default:before,.data-grid-row-changed:after,.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before,.data-grid-search-control-wrap .action-submit:before,.extensions-information .list .extension-delete,.icon-failed:before,.icon-success:before,.notifications-action:before,.notifications-close:before,.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before,.page-title-jumbo-success:before,.search-global-label:before,.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before,.setup-home-item:before,.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before,.store-switcher .dropdown-menu .dropdown-toolbar a:before,.tooltip .help a:before,.tooltip .help span:before{-webkit-font-smoothing:antialiased;font-family:Icons;font-style:normal;font-weight:400;line-height:1;speak:none}.text-stretch{margin-bottom:1.5em}.page-title-jumbo{font-size:4rem;font-weight:300;letter-spacing:-.05em;margin-bottom:2.9rem}.page-title-jumbo-success:before{color:#79a22e;content:'\e62d';font-size:3.9rem;margin-left:-.3rem;margin-right:2.4rem}.list{margin-bottom:3rem}.list-dot .list-item{display:list-item;list-style-position:inside;margin-bottom:1.2rem}.list-title{color:#333;font-size:1.4rem;font-weight:700;letter-spacing:.025em;margin-bottom:1.2rem}.list-item-failed:before,.list-item-success:before,.list-item-warning:before{font-family:Icons;font-size:1.6rem;top:0}.list-item-success:before{content:'\e62d';font-size:1.6rem}.list-item-failed:before{content:'\e632';font-size:1.4rem;left:.1rem;top:.2rem}.list-item-warning:before{content:'\e623';font-size:1.3rem;left:.2rem}.form-wrap{margin-bottom:3.6rem;padding-top:2.1rem}.form-el-label-horizontal{display:inline-block;font-size:1.3rem;font-weight:600;letter-spacing:.025em;margin-bottom:.4rem;margin-left:.4rem}.app-updater{min-width:768px}body._has-modal{height:100%;overflow:hidden;width:100%}.modals-overlay{z-index:899}.modal-popup,.modal-slide{bottom:0;min-width:0;position:fixed;right:0;top:0;visibility:hidden}.modal-popup._show,.modal-slide._show{visibility:visible}.modal-popup._show .modal-inner-wrap,.modal-slide._show .modal-inner-wrap{-ms-transform:translate(0,0);transform:translate(0,0)}.modal-popup .modal-inner-wrap,.modal-slide .modal-inner-wrap{background-color:#fff;box-shadow:0 0 12px 2px rgba(0,0,0,.35);opacity:1;pointer-events:auto}.modal-slide{left:14.8rem;z-index:900}.modal-slide._show .modal-inner-wrap{-ms-transform:translateX(0);transform:translateX(0)}.modal-slide .modal-inner-wrap{height:100%;overflow-y:auto;position:static;-ms-transform:translateX(100%);transform:translateX(100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;width:auto}.modal-slide._inner-scroll .modal-inner-wrap{overflow-y:visible;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.modal-slide._inner-scroll .modal-footer,.modal-slide._inner-scroll .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-slide._inner-scroll .modal-content{overflow-y:auto}.modal-slide._inner-scroll .modal-footer{margin-top:auto}.modal-slide .modal-content,.modal-slide .modal-footer,.modal-slide .modal-header{padding:0 2.6rem 2.6rem}.modal-slide .modal-header{padding-bottom:2.1rem;padding-top:2.1rem}.modal-popup{z-index:900;left:0;overflow-y:auto}.modal-popup._show .modal-inner-wrap{-ms-transform:translateY(0);transform:translateY(0)}.modal-popup .modal-inner-wrap{margin:5rem auto;width:75%;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;box-sizing:border-box;height:auto;left:0;position:absolute;right:0;-ms-transform:translateY(-200%);transform:translateY(-200%);transition-duration:.2s;transition-property:transform,visibility;transition-timing-function:ease}.modal-popup._inner-scroll{overflow-y:visible}.ie10 .modal-popup._inner-scroll,.ie9 .modal-popup._inner-scroll{overflow-y:auto}.modal-popup._inner-scroll .modal-inner-wrap{max-height:90%}.ie10 .modal-popup._inner-scroll .modal-inner-wrap,.ie9 .modal-popup._inner-scroll .modal-inner-wrap{max-height:none}.modal-popup._inner-scroll .modal-content{overflow-y:auto}.modal-popup .modal-content,.modal-popup .modal-footer,.modal-popup .modal-header{padding-left:3rem;padding-right:3rem}.modal-popup .modal-footer,.modal-popup .modal-header{-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0}.modal-popup .modal-header{padding-bottom:1.2rem;padding-top:3rem}.modal-popup .modal-footer{margin-top:auto;padding-bottom:3rem}.modal-popup .modal-footer-actions{text-align:right}.admin__action-dropdown-wrap{display:inline-block;position:relative}.admin__action-dropdown-wrap .admin__action-dropdown-text:after{left:-6px;right:0}.admin__action-dropdown-wrap .admin__action-dropdown-menu{left:auto;right:0}.admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__action-dropdown-wrap.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin__action-dropdown-wrap._active .admin__action-dropdown-text:after,.admin__action-dropdown-wrap.active .admin__action-dropdown-text:after{background-color:#fff;content:'';height:6px;position:absolute;top:100%}.admin__action-dropdown-wrap._active .admin__action-dropdown-menu,.admin__action-dropdown-wrap.active .admin__action-dropdown-menu{display:block}.admin__action-dropdown-wrap._disabled .admin__action-dropdown{cursor:default}.admin__action-dropdown-wrap._disabled:hover .admin__action-dropdown{color:#333}.admin__action-dropdown{background-color:#fff;border:1px solid transparent;border-bottom:none;border-radius:0;box-shadow:none;color:#333;display:inline-block;font-size:1.3rem;font-weight:400;letter-spacing:-.025em;padding:.7rem 3.3rem .8rem 1.5rem;position:relative;vertical-align:baseline;z-index:2}.admin__action-dropdown._active:after,.admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .admin__action-dropdown:after,.active .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin__action-dropdown:focus,.admin__action-dropdown:hover{background-color:#fff;color:#000;text-decoration:none}.admin__action-dropdown:after{right:1.5rem}.admin__action-dropdown:before{margin-right:1rem}.admin__action-dropdown-menu{background-color:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;line-height:1.36;margin-top:-1px;min-width:120%;padding:.5rem 1rem;position:absolute;top:100%;transition:all .15s ease;z-index:1}.admin__action-dropdown-menu>li{display:block}.admin__action-dropdown-menu>li>a{color:#333;display:block;text-decoration:none;padding:.6rem .5rem}.selectmenu{display:inline-block;position:relative;text-align:left;z-index:1}.selectmenu._active{border-color:#007bdb;z-index:500}.selectmenu .action-delete,.selectmenu .action-edit,.selectmenu .action-save{background-color:transparent;border-color:transparent;box-shadow:none;padding:0 1rem}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover,.selectmenu .action-save:hover{background-color:transparent;border-color:transparent;box-shadow:none}.selectmenu .action-delete:before,.selectmenu .action-edit:before,.selectmenu .action-save:before{content:'\e630'}.selectmenu .action-delete,.selectmenu .action-edit{border:0 solid #fff;border-left-width:1px;bottom:0;position:absolute;right:0;top:0;z-index:1}.selectmenu .action-delete:hover,.selectmenu .action-edit:hover{border:0 solid #fff;border-left-width:1px}.selectmenu .action-save:before{content:'\e625'}.selectmenu .action-edit:before{content:'\e631'}.selectmenu-value{display:inline-block}.selectmenu-value input[type=text]{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;border:0;display:inline;margin:0;width:6rem}body._keyfocus .selectmenu-value input[type=text]:focus{box-shadow:none}.selectmenu-toggle{padding-right:3rem;background:0 0;border-width:0;bottom:0;float:right;position:absolute;right:0;top:0;width:0}.selectmenu-toggle._active:after,.selectmenu-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.1rem;top:50%;transition:all .2s linear;width:0}._active .selectmenu-toggle:after,.active .selectmenu-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.selectmenu-toggle:hover:after{border-color:#000 transparent transparent}.selectmenu-toggle:active,.selectmenu-toggle:focus,.selectmenu-toggle:hover{background:0 0}.selectmenu._active .selectmenu-toggle:before{border-color:#007bdb}body._keyfocus .selectmenu-toggle:focus{box-shadow:none}.selectmenu-toggle:before{background:#e3e3e3;border-left:1px solid #adadad;bottom:0;content:'';display:block;position:absolute;right:0;top:0;width:3.2rem}.selectmenu-items{background:#fff;border:1px solid #007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);display:none;float:left;left:-1px;margin-top:3px;max-width:20rem;min-width:calc(100% + 2px);position:absolute;top:100%}.selectmenu-items._active{display:block}.selectmenu-items ul{float:left;list-style-type:none;margin:0;min-width:100%;padding:0}.selectmenu-items li{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row;transition:background .2s linear}.selectmenu-items li:hover{background:#e3e3e3}.selectmenu-items li:last-child .selectmenu-item-action,.selectmenu-items li:last-child .selectmenu-item-action:visited{color:#008bdb;text-decoration:none}.selectmenu-items li:last-child .selectmenu-item-action:hover{color:#0fa7ff;text-decoration:underline}.selectmenu-items li:last-child .selectmenu-item-action:active{color:#ff5501;text-decoration:underline}.selectmenu-item{position:relative;width:100%;z-index:1}li._edit>.selectmenu-item{display:none}.selectmenu-item-edit{display:none;padding:.3rem 4rem .3rem .4rem;position:relative;white-space:nowrap;z-index:1}li:last-child .selectmenu-item-edit{padding-right:.4rem}.selectmenu-item-edit .admin__control-text{margin:0;width:5.4rem}li._edit .selectmenu-item-edit{display:block}.selectmenu-item-action{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background:0 0;border:0;color:#333;display:block;font-size:1.4rem;font-weight:400;min-width:100%;padding:1rem 6rem 1rem 1.5rem;text-align:left;transition:background .2s linear;width:5rem}.selectmenu-item-action:focus,.selectmenu-item-action:hover{background:#e3e3e3}.abs-actions-split-xl .action-default,.page-actions .actions-split .action-default{margin-right:4rem}.abs-actions-split-xl .action-toggle,.page-actions .actions-split .action-toggle{padding-right:4rem}.abs-actions-split-xl .action-toggle:after,.page-actions .actions-split .action-toggle:after{border-width:.9rem .6rem 0;margin-top:-.3rem;right:1.4rem}.actions-split{position:relative;z-index:400}.actions-split._active,.actions-split.active,.actions-split:hover{box-shadow:0 0 0 1px #007bdb}.actions-split._active .action-toggle.action-primary,.actions-split._active .action-toggle.primary,.actions-split.active .action-toggle.action-primary,.actions-split.active .action-toggle.primary{background-color:#ba4000;border-color:#ba4000}.actions-split._active .dropdown-menu,.actions-split.active .dropdown-menu{opacity:1;visibility:visible;display:block}.actions-split .action-default,.actions-split .action-toggle{float:left;margin:0}.actions-split .action-default._active,.actions-split .action-default.active,.actions-split .action-default:hover,.actions-split .action-toggle._active,.actions-split .action-toggle.active,.actions-split .action-toggle:hover{box-shadow:none}.actions-split .action-default{margin-right:3.2rem;min-width:9.3rem}.actions-split .action-toggle{padding-right:3.2rem;border-left-color:rgba(0,0,0,.2);bottom:0;padding-left:0;position:absolute;right:0;top:0}.actions-split .action-toggle._active:after,.actions-split .action-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .actions-split .action-toggle:after,.active .actions-split .action-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.actions-split .action-toggle:hover:after{border-color:#000 transparent transparent}.actions-split .action-toggle.action-primary:after,.actions-split .action-toggle.action-secondary:after,.actions-split .action-toggle.primary:after,.actions-split .action-toggle.secondary:after{border-color:#fff transparent transparent}.actions-split .action-toggle>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-select-wrap{display:inline-block;position:relative}.action-select-wrap .action-select{padding-right:3.2rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background-color:#fff;font-weight:400;text-align:left}.action-select-wrap .action-select._active:after,.action-select-wrap .action-select.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.2rem;top:50%;transition:all .2s linear;width:0}._active .action-select-wrap .action-select:after,.active .action-select-wrap .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .action-select:hover:after{border-color:#000 transparent transparent}.action-select-wrap .action-select:hover,.action-select-wrap .action-select:hover:before{border-color:#878787}.action-select-wrap .action-select:before{background-color:#e3e3e3;border:1px solid #adadad;bottom:0;content:'';position:absolute;right:0;top:0;width:3.2rem}.action-select-wrap .action-select._active{border-color:#007bdb}.action-select-wrap .action-select._active:before{border-color:#007bdb #007bdb #007bdb #adadad}.action-select-wrap .action-select[disabled]{color:#333}.action-select-wrap .action-select[disabled]:after{border-color:#333 transparent transparent}.action-select-wrap._active{z-index:500}.action-select-wrap._active .action-select,.action-select-wrap._active .action-select:before{border-color:#007bdb}.action-select-wrap._active .action-select:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-select-wrap .abs-action-menu .action-submenu,.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu,.action-select-wrap .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:45rem;overflow-y:auto}.action-select-wrap .abs-action-menu .action-submenu ._disabled:hover,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .action-menu ._disabled:hover,.action-select-wrap .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled:hover,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled:hover{background:#fff}.action-select-wrap .abs-action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .abs-action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .action-menu ._disabled .action-menu-item,.action-select-wrap .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu ._disabled .action-menu-item,.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu ._disabled .action-menu-item{cursor:default;opacity:.5}.action-select-wrap .action-menu-items{left:0;position:absolute;right:0;top:100%}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu{min-width:100%;position:static}.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.abs-action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu,.action-select-wrap .action-menu-items>.action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .action-menu .action-submenu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu,.action-select-wrap .action-menu-items>.actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{position:absolute}.action-multicheck-wrap{display:inline-block;height:1.6rem;padding-top:1px;position:relative;width:3.1rem;z-index:200}.action-multicheck-wrap:hover .action-multicheck-toggle,.action-multicheck-wrap:hover .admin__control-checkbox+label:before{border-color:#878787}.action-multicheck-wrap._active .action-multicheck-toggle,.action-multicheck-wrap._active .admin__control-checkbox+label:before{border-color:#007bdb}.action-multicheck-wrap._active .abs-action-menu .action-submenu,.action-multicheck-wrap._active .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .action-menu,.action-multicheck-wrap._active .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu,.action-multicheck-wrap._active .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap._active .actions-split .dropdown-menu .action-submenu .action-submenu{opacity:1;visibility:visible;display:block}.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{background-color:#fff}.action-multicheck-wrap._disabled .action-multicheck-toggle,.action-multicheck-wrap._disabled .admin__control-checkbox+label:before{border-color:#adadad;opacity:1}.action-multicheck-wrap .action-multicheck-toggle,.action-multicheck-wrap .admin__control-checkbox,.action-multicheck-wrap .admin__control-checkbox+label{float:left}.action-multicheck-wrap .action-multicheck-toggle{border-radius:0 1px 1px 0;height:1.6rem;margin-left:-1px;padding:0;position:relative;transition:border-color .1s linear;width:1.6rem}.action-multicheck-wrap .action-multicheck-toggle._active:after,.action-multicheck-wrap .action-multicheck-toggle.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:after{border-color:#000 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;top:50%;transition:all .2s linear;width:0}._active .action-multicheck-wrap .action-multicheck-toggle:after,.active .action-multicheck-wrap .action-multicheck-toggle:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.action-multicheck-wrap .action-multicheck-toggle:hover:after{border-color:#000 transparent transparent}.action-multicheck-wrap .action-multicheck-toggle:focus{border-color:#007bdb}.action-multicheck-wrap .action-multicheck-toggle:after{right:.3rem}.action-multicheck-wrap .abs-action-menu .action-submenu,.action-multicheck-wrap .abs-action-menu .action-submenu .action-submenu,.action-multicheck-wrap .action-menu,.action-multicheck-wrap .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu,.action-multicheck-wrap .actions-split .action-menu .action-submenu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu,.action-multicheck-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:-1.1rem;margin-top:1px;right:auto;text-align:left}.action-multicheck-wrap .action-menu-item{white-space:nowrap}.admin__action-multiselect-wrap{display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.admin__action-multiselect-wrap.action-select-wrap:focus{box-shadow:none}.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .action-menu,.admin__action-multiselect-wrap.action-select-wrap .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-wrap.action-select-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:none;overflow-y:inherit}.admin__action-multiselect-wrap .action-menu-item{transition:background-color .1s linear}.admin__action-multiselect-wrap .action-menu-item._selected{background-color:#e0f6fe}.admin__action-multiselect-wrap .action-menu-item._hover{background-color:#e3e3e3}.admin__action-multiselect-wrap .action-menu-item._unclickable{cursor:default}.admin__action-multiselect-wrap .admin__action-multiselect{border:1px solid #adadad;cursor:pointer;display:block;min-height:3.2rem;padding-right:3.6rem;white-space:normal}.admin__action-multiselect-wrap .admin__action-multiselect:after{bottom:1.25rem;top:auto}.admin__action-multiselect-wrap .admin__action-multiselect:before{height:3.3rem;top:auto}.admin__control-table-wrapper .admin__action-multiselect-wrap{position:static}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect{position:relative}.admin__control-table-wrapper .admin__action-multiselect-wrap .admin__action-multiselect:before{right:-1px;top:-1px}.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .abs-action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu,.admin__control-table-wrapper .admin__action-multiselect-wrap .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .action-menu .action-submenu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu,.admin__control-table-wrapper .admin__action-multiselect-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:34rem;right:auto;top:auto;z-index:1}.admin__action-multiselect-wrap .admin__action-multiselect-item-path{color:#a79d95;font-size:1.2rem;font-weight:400;padding-left:1rem}.admin__action-multiselect-actions-wrap{border-top:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;text-align:center}.admin__action-multiselect-actions-wrap .action-default{font-size:1.3rem;min-width:13rem}.admin__action-multiselect-text{padding:.6rem 1rem}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{text-align:left}.admin__action-multiselect-label{cursor:pointer;position:relative;z-index:1}.admin__action-multiselect-label:before{margin-right:.5rem}._unclickable .admin__action-multiselect-label{cursor:default;font-weight:700}.admin__action-multiselect-search-wrap{border-bottom:1px solid #e3e3e3;margin:0 1rem;padding:1rem 0;position:relative}.admin__action-multiselect-search{padding-right:3rem;width:100%}.admin__action-multiselect-search-label{display:block;font-size:1.5rem;height:1em;overflow:hidden;position:absolute;right:2.2rem;top:1.7rem;width:1em}.admin__action-multiselect-search-label:before{content:'\e60c'}.admin__action-multiselect-search-count{color:#a79d95;margin-top:1rem}.admin__action-multiselect-menu-inner{margin-bottom:0;max-height:46rem;overflow-y:auto}.admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{list-style:none;max-height:none;overflow:hidden;padding-left:2.2rem}.admin__action-multiselect-menu-inner ._hidden{display:none}.admin__action-multiselect-crumb{background-color:#f5f5f5;border:1px solid #a79d95;border-radius:1px;display:inline-block;font-size:1.2rem;margin:.3rem -4px .3rem .3rem;padding:.3rem 2.4rem .4rem 1rem;position:relative;transition:border-color .1s linear}.admin__action-multiselect-crumb:hover{border-color:#908379}.admin__action-multiselect-crumb .action-close{bottom:0;font-size:.5em;position:absolute;right:0;top:0;width:2rem}.admin__action-multiselect-crumb .action-close:hover{color:#000}.admin__action-multiselect-crumb .action-close:active,.admin__action-multiselect-crumb .action-close:focus{background-color:transparent}.admin__action-multiselect-crumb .action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__action-multiselect-tree .abs-action-menu .action-submenu,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .action-menu,.admin__action-multiselect-tree .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu{min-width:34.7rem}.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .abs-action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-menu-item,.admin__action-multiselect-tree .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-menu-item,.admin__action-multiselect-tree .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item{margin-top:.1rem}.admin__action-multiselect-tree .action-menu-item{margin-left:4.2rem;position:relative}.admin__action-multiselect-tree .action-menu-item._expended:before{border-left:1px dashed #a79d95;bottom:0;content:'';left:-1rem;position:absolute;top:1rem;width:1px}.admin__action-multiselect-tree .action-menu-item._expended .admin__action-multiselect-dropdown:before{content:'\e615'}.admin__action-multiselect-tree .action-menu-item._with-checkbox .admin__action-multiselect-label{padding-left:2.6rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner{padding-left:3.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner .admin__action-multiselect-menu-inner:before{left:4.3rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item{position:relative}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:last-child:before{height:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after,.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{content:'';left:0;position:absolute}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:after{border-top:1px dashed #a79d95;height:1px;top:2.1rem;width:5.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item:before{border-left:1px dashed #a79d95;height:100%;top:0;width:1px}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._parent:after{width:4.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root{margin-left:-1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:after{left:3.2rem;width:2.2rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:before{left:3.2rem;top:1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root._parent:after{display:none}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:first-child:before{top:2.1rem}.admin__action-multiselect-tree .admin__action-multiselect-menu-inner-item._root:last-child:before{height:1rem}.admin__action-multiselect-tree .admin__action-multiselect-label{line-height:2.2rem;vertical-align:middle;word-break:break-all}.admin__action-multiselect-tree .admin__action-multiselect-label:before{left:0;position:absolute;top:.4rem}.admin__action-multiselect-dropdown{border-radius:50%;height:2.2rem;left:-2.2rem;position:absolute;top:1rem;width:2.2rem;z-index:1}.admin__action-multiselect-dropdown:before{background:#fff;color:#a79d95;content:'\e616';font-size:2.2rem}.admin__actions-switch{display:inline-block;position:relative;vertical-align:middle}.admin__field-control .admin__actions-switch{line-height:3.2rem}.admin__actions-switch+.admin__field-service{min-width:34rem}._disabled .admin__actions-switch-checkbox+.admin__actions-switch-label,.admin__actions-switch-checkbox.disabled+.admin__actions-switch-label{cursor:not-allowed;opacity:.5;pointer-events:none}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:before{left:15px}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label:after{background:#79a22e}.admin__actions-switch-checkbox:checked+.admin__actions-switch-label .admin__actions-switch-text:before{content:attr(data-text-on)}.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:after,.admin__actions-switch-checkbox:focus+.admin__actions-switch-label:before{border-color:#007bdb}._error .admin__actions-switch-checkbox+.admin__actions-switch-label:after,._error .admin__actions-switch-checkbox+.admin__actions-switch-label:before{border-color:#e22626}.admin__actions-switch-label{cursor:pointer;display:inline-block;height:22px;line-height:22px;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}.admin__actions-switch-label:after,.admin__actions-switch-label:before{left:0;position:absolute;right:auto;top:0}.admin__actions-switch-label:before{background:#fff;border:1px solid #aaa6a0;border-radius:100%;content:'';display:block;height:22px;transition:left .2s ease-in 0s;width:22px;z-index:1}.admin__actions-switch-label:after{background:#e3e3e3;border:1px solid #aaa6a0;border-radius:12px;content:'';display:block;height:22px;transition:background .2s ease-in 0s;vertical-align:middle;width:37px;z-index:0}.admin__actions-switch-text:before{content:attr(data-text-off);padding-left:47px;white-space:nowrap}.abs-action-delete,.abs-action-reset,.action-close,.admin__field-fallback-reset,.extensions-information .list .extension-delete,.notifications-close,.search-global-field._active .search-global-action{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0}.abs-action-delete:hover,.abs-action-reset:hover,.action-close:hover,.admin__field-fallback-reset:hover,.extensions-information .list .extension-delete:hover,.notifications-close:hover,.search-global-field._active .search-global-action:hover{background-color:transparent;border:none;box-shadow:none}.abs-action-default,.abs-action-pattern,.abs-action-primary,.abs-action-quaternary,.abs-action-secondary,.abs-action-tertiary,.action-default,.action-primary,.action-quaternary,.action-secondary,.action-tertiary,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions>button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary,button,button.primary,button.secondary,button.tertiary{border:1px solid;border-radius:0;display:inline-block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:1.36;padding:.6rem 1em;text-align:center;vertical-align:baseline}.abs-action-default.disabled,.abs-action-default[disabled],.abs-action-pattern.disabled,.abs-action-pattern[disabled],.abs-action-primary.disabled,.abs-action-primary[disabled],.abs-action-quaternary.disabled,.abs-action-quaternary[disabled],.abs-action-secondary.disabled,.abs-action-secondary[disabled],.abs-action-tertiary.disabled,.abs-action-tertiary[disabled],.action-default.disabled,.action-default[disabled],.action-primary.disabled,.action-primary[disabled],.action-quaternary.disabled,.action-quaternary[disabled],.action-secondary.disabled,.action-secondary[disabled],.action-tertiary.disabled,.action-tertiary[disabled],.modal-popup .modal-footer .action-primary.disabled,.modal-popup .modal-footer .action-primary[disabled],.modal-popup .modal-footer .action-secondary.disabled,.modal-popup .modal-footer .action-secondary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.action-secondary.disabled,.page-actions .page-actions-buttons>button.action-secondary[disabled],.page-actions .page-actions-buttons>button.disabled,.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions .page-actions-buttons>button[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.action-secondary.disabled,.page-actions>button.action-secondary[disabled],.page-actions>button.disabled,.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],.page-actions>button[disabled],button.disabled,button.primary.disabled,button.primary[disabled],button.secondary.disabled,button.secondary[disabled],button.tertiary.disabled,button.tertiary[disabled],button[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-l,.modal-popup .modal-footer .action-primary,.modal-popup .modal-footer .action-secondary,.page-actions .page-actions-buttons>button,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions .page-actions-buttons>button.primary,.page-actions button,.page-actions>button.action-primary,.page-actions>button.action-secondary,.page-actions>button.primary{font-size:1.6rem;letter-spacing:.025em;padding-bottom:.6875em;padding-top:.6875em}.abs-action-delete,.extensions-information .list .extension-delete{display:inline-block;font-size:1.6rem;margin-left:1.2rem;padding-top:.7rem;text-decoration:none;vertical-align:middle}.abs-action-delete:after,.extensions-information .list .extension-delete:after{color:#666;content:'\e630'}.abs-action-delete:hover:after,.extensions-information .list .extension-delete:hover:after{color:#35302c}.abs-action-button-as-link,.action-advanced,.data-grid .action-delete{line-height:1.36;padding:0;color:#008bdb;text-decoration:none;background:0 0;border:0;display:inline;font-weight:400;border-radius:0}.abs-action-button-as-link:visited,.action-advanced:visited,.data-grid .action-delete:visited{color:#008bdb;text-decoration:none}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{text-decoration:underline}.abs-action-button-as-link:active,.action-advanced:active,.data-grid .action-delete:active{color:#ff5501;text-decoration:underline}.abs-action-button-as-link:hover,.action-advanced:hover,.data-grid .action-delete:hover{color:#0fa7ff}.abs-action-button-as-link:active,.abs-action-button-as-link:focus,.abs-action-button-as-link:hover,.action-advanced:active,.action-advanced:focus,.action-advanced:hover,.data-grid .action-delete:active,.data-grid .action-delete:focus,.data-grid .action-delete:hover{background:0 0;border:0}.abs-action-button-as-link.disabled,.abs-action-button-as-link[disabled],.action-advanced.disabled,.action-advanced[disabled],.data-grid .action-delete.disabled,.data-grid .action-delete[disabled],fieldset[disabled] .abs-action-button-as-link,fieldset[disabled] .action-advanced,fieldset[disabled] .data-grid .action-delete{color:#008bdb;opacity:.5;cursor:default;pointer-events:none;text-decoration:underline}.abs-action-button-as-link:active,.abs-action-button-as-link:not(:focus),.action-advanced:active,.action-advanced:not(:focus),.data-grid .action-delete:active,.data-grid .action-delete:not(:focus){box-shadow:none}.abs-action-button-as-link:focus,.action-advanced:focus,.data-grid .action-delete:focus{color:#0fa7ff}.abs-action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.abs-action-default:active,.abs-action-default:focus,.abs-action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.abs-action-primary,.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary,button.primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.abs-action-primary:active,.abs-action-primary:focus,.abs-action-primary:hover,.page-actions .page-actions-buttons>button.action-primary:active,.page-actions .page-actions-buttons>button.action-primary:focus,.page-actions .page-actions-buttons>button.action-primary:hover,.page-actions .page-actions-buttons>button.primary:active,.page-actions .page-actions-buttons>button.primary:focus,.page-actions .page-actions-buttons>button.primary:hover,.page-actions>button.action-primary:active,.page-actions>button.action-primary:focus,.page-actions>button.action-primary:hover,.page-actions>button.primary:active,.page-actions>button.primary:focus,.page-actions>button.primary:hover,button.primary:active,button.primary:focus,button.primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-primary.disabled,.abs-action-primary[disabled],.page-actions .page-actions-buttons>button.action-primary.disabled,.page-actions .page-actions-buttons>button.action-primary[disabled],.page-actions .page-actions-buttons>button.primary.disabled,.page-actions .page-actions-buttons>button.primary[disabled],.page-actions>button.action-primary.disabled,.page-actions>button.action-primary[disabled],.page-actions>button.primary.disabled,.page-actions>button.primary[disabled],button.primary.disabled,button.primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.abs-action-secondary,.modal-popup .modal-footer .action-primary,.page-actions .page-actions-buttons>button.action-secondary,.page-actions>button.action-secondary,button.secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.abs-action-secondary:active,.abs-action-secondary:focus,.abs-action-secondary:hover,.modal-popup .modal-footer .action-primary:active,.modal-popup .modal-footer .action-primary:focus,.modal-popup .modal-footer .action-primary:hover,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions .page-actions-buttons>button.action-secondary:focus,.page-actions .page-actions-buttons>button.action-secondary:hover,.page-actions>button.action-secondary:active,.page-actions>button.action-secondary:focus,.page-actions>button.action-secondary:hover,button.secondary:active,button.secondary:focus,button.secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.abs-action-secondary:active,.modal-popup .modal-footer .action-primary:active,.page-actions .page-actions-buttons>button.action-secondary:active,.page-actions>button.action-secondary:active,button.secondary:active{background-color:#35302c}.abs-action-tertiary,.modal-popup .modal-footer .action-secondary,button.tertiary{background-color:transparent;border-color:transparent;text-shadow:none;color:#008bdb}.abs-action-tertiary:active,.abs-action-tertiary:focus,.abs-action-tertiary:hover,.modal-popup .modal-footer .action-secondary:active,.modal-popup .modal-footer .action-secondary:focus,.modal-popup .modal-footer .action-secondary:hover,button.tertiary:active,button.tertiary:focus,button.tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#0fa7ff;text-decoration:underline}.abs-action-quaternary,.page-actions .page-actions-buttons>button,.page-actions>button{background-color:transparent;border-color:transparent;text-shadow:none;color:#333}.abs-action-quaternary:active,.abs-action-quaternary:focus,.abs-action-quaternary:hover,.page-actions .page-actions-buttons>button:active,.page-actions .page-actions-buttons>button:focus,.page-actions .page-actions-buttons>button:hover,.page-actions>button:active,.page-actions>button:focus,.page-actions>button:hover{background-color:transparent;border-color:transparent;box-shadow:none;color:#1a1a1a}.abs-action-menu,.actions-split .abs-action-menu .action-submenu,.actions-split .abs-action-menu .action-submenu .action-submenu,.actions-split .action-menu,.actions-split .action-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.actions-split .dropdown-menu{text-align:left;background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu._active,.actions-split .abs-action-menu .action-submenu .action-submenu._active,.actions-split .abs-action-menu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .action-menu._active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .actions-split .dropdown-menu .action-submenu._active,.actions-split .dropdown-menu._active{display:block}.abs-action-menu>li,.actions-split .abs-action-menu .action-submenu .action-submenu>li,.actions-split .abs-action-menu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .action-menu>li,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .actions-split .dropdown-menu .action-submenu>li,.actions-split .dropdown-menu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu>li>a:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .abs-action-menu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .action-menu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu>li>a:hover{text-decoration:none}.abs-action-menu>li._visible,.abs-action-menu>li:hover,.actions-split .abs-action-menu .action-submenu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu .action-submenu>li:hover,.actions-split .abs-action-menu .action-submenu>li._visible,.actions-split .abs-action-menu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .action-menu>li._visible,.actions-split .action-menu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .actions-split .dropdown-menu .action-submenu>li:hover,.actions-split .dropdown-menu>li._visible,.actions-split .dropdown-menu>li:hover{background-color:#e3e3e3}.abs-action-menu>li:active,.actions-split .abs-action-menu .action-submenu .action-submenu>li:active,.actions-split .abs-action-menu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .action-menu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .actions-split .dropdown-menu .action-submenu>li:active,.actions-split .dropdown-menu>li:active{background-color:#cacaca}.abs-action-menu>li._parent,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent,.actions-split .abs-action-menu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .action-menu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent,.actions-split .dropdown-menu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .abs-action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-menu-item,.abs-action-menu .item,.actions-split .abs-action-menu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu .item,.actions-split .abs-action-menu .action-submenu .item,.actions-split .action-menu .action-menu-item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .item,.actions-split .action-menu .item,.actions-split .actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .actions-split .dropdown-menu .action-submenu .item,.actions-split .dropdown-menu .action-menu-item,.actions-split .dropdown-menu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu,.ie9 .actions-split .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu a.action-menu-item,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .abs-action-menu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .action-menu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu a.action-menu-item{color:#333}.abs-action-menu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .abs-action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .action-menu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .actions-split .dropdown-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.abs-action-wrap-triangle{position:relative}.abs-action-wrap-triangle .action-default{width:100%}.abs-action-wrap-triangle .action-default:after,.abs-action-wrap-triangle .action-default:before{border-style:solid;content:'';height:0;position:absolute;top:0;width:0}.abs-action-wrap-triangle .action-default:active,.abs-action-wrap-triangle .action-default:focus,.abs-action-wrap-triangle .action-default:hover{box-shadow:none}._keyfocus .abs-action-wrap-triangle .action-default:focus{box-shadow:0 0 0 1px #007bdb}.ie10 .abs-action-wrap-triangle .action-default.disabled,.ie10 .abs-action-wrap-triangle .action-default[disabled],.ie9 .abs-action-wrap-triangle .action-default.disabled,.ie9 .abs-action-wrap-triangle .action-default[disabled]{background-color:#fcfcfc;opacity:1;text-shadow:none}.abs-action-wrap-triangle-right{display:inline-block;padding-right:1.6rem;position:relative}.abs-action-wrap-triangle-right .action-default:after,.abs-action-wrap-triangle-right .action-default:before{border-color:transparent transparent transparent #e3e3e3;border-width:1.7rem 0 1.6rem 1.7rem;left:100%;margin-left:-1.7rem}.abs-action-wrap-triangle-right .action-default:before{border-left-color:#949494;right:-1px}.abs-action-wrap-triangle-right .action-default:active:after,.abs-action-wrap-triangle-right .action-default:focus:after,.abs-action-wrap-triangle-right .action-default:hover:after{border-left-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-right .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-right .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-right .action-default[disabled]:after{border-color:transparent transparent transparent #fcfcfc}.abs-action-wrap-triangle-right .action-primary:after{border-color:transparent transparent transparent #eb5202}.abs-action-wrap-triangle-right .action-primary:active:after,.abs-action-wrap-triangle-right .action-primary:focus:after,.abs-action-wrap-triangle-right .action-primary:hover:after{border-left-color:#ba4000}.abs-action-wrap-triangle-left{display:inline-block;padding-left:1.6rem}.abs-action-wrap-triangle-left .action-default{text-indent:-.85rem}.abs-action-wrap-triangle-left .action-default:after,.abs-action-wrap-triangle-left .action-default:before{border-color:transparent #e3e3e3 transparent transparent;border-width:1.7rem 1.7rem 1.6rem 0;margin-right:-1.7rem;right:100%}.abs-action-wrap-triangle-left .action-default:before{border-right-color:#949494;left:-1px}.abs-action-wrap-triangle-left .action-default:active:after,.abs-action-wrap-triangle-left .action-default:focus:after,.abs-action-wrap-triangle-left .action-default:hover:after{border-right-color:#dbdbdb}.ie10 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie10 .abs-action-wrap-triangle-left .action-default[disabled]:after,.ie9 .abs-action-wrap-triangle-left .action-default.disabled:after,.ie9 .abs-action-wrap-triangle-left .action-default[disabled]:after{border-color:transparent #fcfcfc transparent transparent}.abs-action-wrap-triangle-left .action-primary:after{border-color:transparent #eb5202 transparent transparent}.abs-action-wrap-triangle-left .action-primary:active:after,.abs-action-wrap-triangle-left .action-primary:focus:after,.abs-action-wrap-triangle-left .action-primary:hover:after{border-right-color:#ba4000}.action-default,button{background:#e3e3e3;border-color:#adadad;color:#514943}.action-default:active,.action-default:focus,.action-default:hover,button:active,button:focus,button:hover{background-color:#dbdbdb;color:#514943;text-decoration:none}.action-primary{background-color:#eb5202;border-color:#eb5202;color:#fff;text-shadow:1px 1px 0 rgba(0,0,0,.25)}.action-primary:active,.action-primary:focus,.action-primary:hover{background-color:#ba4000;border-color:#b84002;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-primary.disabled,.action-primary[disabled]{cursor:default;opacity:.5;pointer-events:none}.action-secondary{background-color:#514943;border-color:#514943;color:#fff;text-shadow:1px 1px 1px rgba(0,0,0,.3)}.action-secondary:active,.action-secondary:focus,.action-secondary:hover{background-color:#35302c;border-color:#35302c;box-shadow:0 0 0 1px #007bdb;color:#fff;text-decoration:none}.action-secondary:active{background-color:#35302c}.action-quaternary,.action-tertiary{background-color:transparent;border-color:transparent;text-shadow:none}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover,.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{background-color:transparent;border-color:transparent;box-shadow:none}.action-tertiary{color:#008bdb}.action-tertiary:active,.action-tertiary:focus,.action-tertiary:hover{color:#0fa7ff;text-decoration:underline}.action-quaternary{color:#333}.action-quaternary:active,.action-quaternary:focus,.action-quaternary:hover{color:#1a1a1a}.action-close>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-close:active{-ms-transform:scale(0.9);transform:scale(0.9)}.action-close:before{content:'\e62f';transition:color .1s linear}.action-close:hover{cursor:pointer;text-decoration:none}.abs-action-menu .action-submenu,.abs-action-menu .action-submenu .action-submenu,.action-menu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{background-color:#fff;border:1px solid #007bdb;border-radius:1px;box-shadow:1px 1px 5px rgba(0,0,0,.5);color:#333;display:none;font-weight:400;left:0;list-style:none;margin:2px 0 0;min-width:0;padding:0;position:absolute;right:0;top:100%}.abs-action-menu .action-submenu .action-submenu._active,.abs-action-menu .action-submenu._active,.action-menu .action-submenu._active,.action-menu._active,.actions-split .action-menu .action-submenu .action-submenu._active,.actions-split .action-menu .action-submenu._active,.actions-split .dropdown-menu .action-submenu .action-submenu._active,.actions-split .dropdown-menu .action-submenu._active{display:block}.abs-action-menu .action-submenu .action-submenu>li,.abs-action-menu .action-submenu>li,.action-menu .action-submenu>li,.action-menu>li,.actions-split .action-menu .action-submenu .action-submenu>li,.actions-split .action-menu .action-submenu>li,.actions-split .dropdown-menu .action-submenu .action-submenu>li,.actions-split .dropdown-menu .action-submenu>li{border:none;display:block;padding:0;transition:background-color .1s linear}.abs-action-menu .action-submenu .action-submenu>li>a:hover,.abs-action-menu .action-submenu>li>a:hover,.action-menu .action-submenu>li>a:hover,.action-menu>li>a:hover,.actions-split .action-menu .action-submenu .action-submenu>li>a:hover,.actions-split .action-menu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li>a:hover,.actions-split .dropdown-menu .action-submenu>li>a:hover{text-decoration:none}.abs-action-menu .action-submenu .action-submenu>li._visible,.abs-action-menu .action-submenu .action-submenu>li:hover,.abs-action-menu .action-submenu>li._visible,.abs-action-menu .action-submenu>li:hover,.action-menu .action-submenu>li._visible,.action-menu .action-submenu>li:hover,.action-menu>li._visible,.action-menu>li:hover,.actions-split .action-menu .action-submenu .action-submenu>li._visible,.actions-split .action-menu .action-submenu .action-submenu>li:hover,.actions-split .action-menu .action-submenu>li._visible,.actions-split .action-menu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu .action-submenu>li:hover,.actions-split .dropdown-menu .action-submenu>li._visible,.actions-split .dropdown-menu .action-submenu>li:hover{background-color:#e3e3e3}.abs-action-menu .action-submenu .action-submenu>li:active,.abs-action-menu .action-submenu>li:active,.action-menu .action-submenu>li:active,.action-menu>li:active,.actions-split .action-menu .action-submenu .action-submenu>li:active,.actions-split .action-menu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu .action-submenu>li:active,.actions-split .dropdown-menu .action-submenu>li:active{background-color:#cacaca}.abs-action-menu .action-submenu .action-submenu>li._parent,.abs-action-menu .action-submenu>li._parent,.action-menu .action-submenu>li._parent,.action-menu>li._parent,.actions-split .action-menu .action-submenu .action-submenu>li._parent,.actions-split .action-menu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent,.actions-split .dropdown-menu .action-submenu>li._parent{-webkit-flex-direction:row;display:flex;-ms-flex-direction:row;flex-direction:row}.abs-action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.abs-action-menu .action-submenu>li._parent>.action-menu-item,.action-menu .action-submenu>li._parent>.action-menu-item,.action-menu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .action-menu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu>li._parent>.action-menu-item,.actions-split .dropdown-menu .action-submenu>li._parent>.action-menu-item{min-width:100%}.abs-action-menu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .action-menu-item,.abs-action-menu .action-submenu .action-submenu .item,.abs-action-menu .action-submenu .item,.action-menu .action-menu-item,.action-menu .action-submenu .action-menu-item,.action-menu .action-submenu .item,.action-menu .item,.actions-split .action-menu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .action-menu-item,.actions-split .action-menu .action-submenu .action-submenu .item,.actions-split .action-menu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu .item,.actions-split .dropdown-menu .action-submenu .item{cursor:pointer;display:block;padding:.6875em 1em}.abs-action-menu .action-submenu .action-submenu,.action-menu .action-submenu,.actions-split .action-menu .action-submenu .action-submenu,.actions-split .dropdown-menu .action-submenu .action-submenu{bottom:auto;left:auto;margin-left:0;margin-top:-1px;position:absolute;right:auto;top:auto}.ie9 .abs-action-menu .action-submenu .action-submenu,.ie9 .abs-action-menu .action-submenu .action-submenu .action-submenu,.ie9 .action-menu .action-submenu,.ie9 .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu,.ie9 .actions-split .action-menu .action-submenu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu,.ie9 .actions-split .dropdown-menu .action-submenu .action-submenu .action-submenu{margin-left:99%;margin-top:-3.5rem}.abs-action-menu .action-submenu .action-submenu a.action-menu-item,.abs-action-menu .action-submenu a.action-menu-item,.action-menu .action-submenu a.action-menu-item,.action-menu a.action-menu-item,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .action-menu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item,.actions-split .dropdown-menu .action-submenu a.action-menu-item{color:#333}.abs-action-menu .action-submenu .action-submenu a.action-menu-item:focus,.abs-action-menu .action-submenu a.action-menu-item:focus,.action-menu .action-submenu a.action-menu-item:focus,.action-menu a.action-menu-item:focus,.actions-split .action-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .action-menu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu .action-submenu a.action-menu-item:focus,.actions-split .dropdown-menu .action-submenu a.action-menu-item:focus{background-color:#e3e3e3;box-shadow:none}.messages .message:last-child{margin:0 0 2rem}.message{background:#fffbbb;border:none;border-radius:0;color:#333;font-size:1.4rem;margin:0 0 1px;padding:1.8rem 4rem 1.8rem 5.5rem;position:relative;text-shadow:none}.message:before{background:0 0;border:0;color:#007bdb;content:'\e61a';font-family:Icons;font-size:1.9rem;font-style:normal;font-weight:400;height:auto;left:1.9rem;line-height:inherit;margin-top:-1.3rem;position:absolute;speak:none;text-shadow:none;top:50%;width:auto}.message-notice:before{color:#007bdb;content:'\e61a'}.message-warning:before{color:#eb5202;content:'\e623'}.message-error{background:#fcc}.message-error:before{color:#e22626;content:'\e632';font-size:1.5rem;left:2.2rem;margin-top:-1rem}.message-success:before{color:#79a22e;content:'\e62d'}.message-spinner:before{display:none}.message-spinner .spinner{font-size:2.5rem;left:1.5rem;position:absolute;top:1.5rem}.message-in-rating-edit{margin-left:1.8rem;margin-right:1.8rem}.modal-popup .action-close,.modal-slide .action-close{color:#736963;position:absolute;right:0;top:0;z-index:1}.modal-popup .action-close:active,.modal-slide .action-close:active{-ms-transform:none;transform:none}.modal-popup .action-close:active:before,.modal-slide .action-close:active:before{font-size:1.8rem}.modal-popup .action-close:hover:before,.modal-slide .action-close:hover:before{color:#58504b}.modal-popup .action-close:before,.modal-slide .action-close:before{font-size:2rem}.modal-popup .action-close:focus,.modal-slide .action-close:focus{background-color:transparent}.modal-popup.prompt .prompt-message{padding:2rem 0}.modal-popup.prompt .prompt-message input{width:100%}.modal-popup.confirm .modal-inner-wrap .message,.modal-popup.prompt .modal-inner-wrap .message{background:#fff}.modal-popup.modal-system-messages .modal-inner-wrap{background:#fffbbb}.modal-popup._image-box .modal-inner-wrap{margin:5rem auto;max-width:78rem;position:static}.modal-popup._image-box .thumbnail-preview{padding-bottom:3rem;text-align:center}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image-block{border:1px solid #ccc;margin:0 auto 2rem;max-width:58rem;padding:2rem}.modal-popup._image-box .thumbnail-preview .thumbnail-preview-image{max-height:54rem}.modal-popup .modal-title{font-size:2.4rem;margin-right:6.4rem}.modal-popup .modal-footer{padding-top:2.6rem;text-align:right}.modal-popup .action-close{padding:3rem}.modal-popup .action-close:active,.modal-popup .action-close:focus{background:0 0;padding-right:3.1rem;padding-top:3.1rem}.modal-slide .modal-content-new-attribute{-webkit-overflow-scrolling:touch;overflow:auto;padding-bottom:0}.modal-slide .modal-content-new-attribute iframe{margin-bottom:-2.5rem}.modal-slide .modal-title{font-size:2.1rem;margin-right:5.7rem}.modal-slide .action-close{padding:2.1rem 2.6rem}.modal-slide .action-close:active{padding-right:2.7rem;padding-top:2.2rem}.modal-slide .page-main-actions{margin-bottom:.6rem;margin-top:2.1rem}.modal-slide .magento-message{padding:0 3rem 3rem;position:relative}.modal-slide .magento-message .insert-title-inner,.modal-slide .main-col .insert-title-inner{border-bottom:1px solid #adadad;margin:0 0 2rem;padding-bottom:.5rem}.modal-slide .magento-message .insert-actions,.modal-slide .main-col .insert-actions{float:right}.modal-slide .magento-message .title,.modal-slide .main-col .title{font-size:1.6rem;padding-top:.5rem}.modal-slide .main-col,.modal-slide .side-col{float:left;padding-bottom:0}.modal-slide .main-col:after,.modal-slide .side-col:after{display:none}.modal-slide .side-col{width:20%}.modal-slide .main-col{padding-right:0;width:80%}.modal-slide .content-footer .form-buttons{float:right}.modal-title{font-weight:400;margin-bottom:0;min-height:1em}.modal-title span{font-size:1.4rem;font-style:italic;margin-left:1rem}.spinner{display:inline-block;font-size:4rem;height:1em;margin-right:1.5rem;position:relative;width:1em}.spinner>span:nth-child(1){animation-delay:.27s;-ms-transform:rotate(-315deg);transform:rotate(-315deg)}.spinner>span:nth-child(2){animation-delay:.36s;-ms-transform:rotate(-270deg);transform:rotate(-270deg)}.spinner>span:nth-child(3){animation-delay:.45s;-ms-transform:rotate(-225deg);transform:rotate(-225deg)}.spinner>span:nth-child(4){animation-delay:.54s;-ms-transform:rotate(-180deg);transform:rotate(-180deg)}.spinner>span:nth-child(5){animation-delay:.63s;-ms-transform:rotate(-135deg);transform:rotate(-135deg)}.spinner>span:nth-child(6){animation-delay:.72s;-ms-transform:rotate(-90deg);transform:rotate(-90deg)}.spinner>span:nth-child(7){animation-delay:.81s;-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.spinner>span:nth-child(8){animation-delay:.9;-ms-transform:rotate(0deg);transform:rotate(0deg)}@keyframes fade{0%{background-color:#514943}100%{background-color:#fff}}.spinner>span{-ms-transform:scale(0.4);transform:scale(0.4);animation-name:fade;animation-duration:.72s;animation-iteration-count:infinite;animation-direction:linear;background-color:#fff;border-radius:6px;clip:rect(0 .28571429em .1em 0);height:.1em;margin-top:.5em;position:absolute;width:1em}.ie9 .spinner{background:url(../images/ajax-loader.gif) center no-repeat}.ie9 .spinner>span{display:none}.popup-loading{background:rgba(255,255,255,.8);border-color:#ef672f;color:#ef672f;font-size:14px;font-weight:700;left:50%;margin-left:-100px;padding:100px 0 10px;position:fixed;text-align:center;top:40%;width:200px;z-index:1003}.popup-loading:after{background-image:url(../images/loader-1.gif);content:'';height:64px;left:50%;margin:-32px 0 0 -32px;position:absolute;top:40%;width:64px;z-index:2}.loading-mask,.loading-old{background:rgba(255,255,255,.4);bottom:0;left:0;position:fixed;right:0;top:0;z-index:2003}.loading-mask img,.loading-old img{display:none}.loading-mask p,.loading-old p{margin-top:118px}.loading-mask .loader,.loading-old .loader{background:url(../images/loader-1.gif) 50% 30% no-repeat #f7f3eb;border-radius:5px;bottom:0;color:#575757;font-size:14px;font-weight:700;height:160px;left:0;margin:auto;opacity:.95;position:absolute;right:0;text-align:center;top:0;width:160px}.admin-user{float:right;line-height:1.36;margin-left:.3rem;z-index:490}.admin-user._active .admin__action-dropdown,.admin-user.active .admin__action-dropdown{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.admin-user .admin__action-dropdown{height:3.3rem;padding:.7rem 2.8rem .4rem 4rem}.admin-user .admin__action-dropdown._active:after,.admin-user .admin__action-dropdown.active:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:after{border-color:#777 transparent transparent;border-style:solid;border-width:.5rem .4rem 0;content:'';height:0;margin-top:-.2rem;position:absolute;right:1.3rem;top:50%;transition:all .2s linear;width:0}._active .admin-user .admin__action-dropdown:after,.active .admin-user .admin__action-dropdown:after{-ms-transform:rotate(180deg);transform:rotate(180deg)}.admin-user .admin__action-dropdown:hover:after{border-color:#000 transparent transparent}.admin-user .admin__action-dropdown:before{color:#777;content:'\e600';font-size:2rem;left:1.1rem;margin-top:-1.1rem;position:absolute;top:50%}.admin-user .admin__action-dropdown:hover:before{color:#333}.admin-user .admin__action-dropdown-menu{min-width:20rem;padding-left:1rem;padding-right:1rem}.admin-user .admin__action-dropdown-menu>li>a{padding-left:.5em;padding-right:1.8rem;transition:background-color .1s linear;white-space:nowrap}.admin-user .admin__action-dropdown-menu>li>a:hover{background-color:#e0f6fe;color:#333}.admin-user .admin__action-dropdown-menu>li>a:active{background-color:#c7effd;bottom:-1px;position:relative}.admin-user .admin__action-dropdown-menu .admin-user-name{text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:20rem;overflow:hidden;vertical-align:top}.admin-user-account-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;max-width:11.2rem}.search-global{float:right;margin-right:-.3rem;position:relative;z-index:480}.search-global-field{min-width:5rem}.search-global-field._active .search-global-input{background-color:#fff;border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5);padding-right:4rem;width:25rem}.search-global-field._active .search-global-action{display:block;height:3.3rem;position:absolute;right:0;text-indent:-100%;top:0;width:5rem;z-index:3}.search-global-field .autocomplete-results{height:3.3rem;position:absolute;right:0;top:0;width:25rem}.search-global-field .search-global-menu{border:1px solid #007bdb;border-top-color:transparent;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin-top:-2px;padding:0;position:absolute;right:0;top:100%;z-index:2}.search-global-field .search-global-menu:after{background-color:#fff;content:'';height:5px;left:0;position:absolute;right:0;top:-5px}.search-global-field .search-global-menu>li{background-color:#fff;border-top:1px solid #ddd;display:block;font-size:1.2rem;padding:.75rem 1.4rem .55rem}.search-global-field .search-global-menu>li._active{background-color:#e0f6fe}.search-global-field .search-global-menu .title{display:block;font-size:1.4rem}.search-global-field .search-global-menu .type{color:#1a1a1a;display:block}.search-global-label{cursor:pointer;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;z-index:2}.search-global-label:active{-ms-transform:scale(0.9);transform:scale(0.9)}.search-global-label:hover:before{color:#000}.search-global-label:before{color:#777;content:'\e60c';font-size:2rem}.search-global-input{background-color:transparent;border:1px solid transparent;font-size:1.4rem;height:3.3rem;padding:.75rem 1.4rem .55rem;position:absolute;right:0;top:0;transition:all .1s linear,width .3s linear;width:5rem;z-index:1}.search-global-action{display:none}.notifications-wrapper{float:right;line-height:1;position:relative}.notifications-wrapper.active{z-index:500}.notifications-wrapper.active .notifications-action{border-color:#007bdb;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.notifications-wrapper.active .notifications-action:after{background-color:#fff;border:none;content:'';display:block;height:6px;left:-6px;margin-top:0;position:absolute;right:0;top:100%;width:auto}.notifications-wrapper .admin__action-dropdown-menu{padding:1rem 0 0;width:32rem}.notifications-action{color:#777;height:3.3rem;padding:.75rem 2rem .65rem}.notifications-action:after{display:none}.notifications-action:before{content:'\e607';font-size:1.9rem;margin-right:0}.notifications-action:active:before{position:relative;top:1px}.notifications-action .notifications-counter{background-color:#e22626;border-radius:1em;color:#fff;display:inline-block;font-size:1.1rem;font-weight:700;left:50%;margin-left:.3em;margin-top:-1.1em;padding:.3em .5em;position:absolute;top:50%}.notifications-entry{line-height:1.36;padding:.6rem 2rem .8rem;position:relative;transition:background-color .1s linear}.notifications-entry:hover{background-color:#e0f6fe}.notifications-entry.notifications-entry-last{margin:0 2rem;padding:.3rem 0 1.3rem;text-align:center}.notifications-entry.notifications-entry-last:hover{background-color:transparent}.notifications-entry+.notifications-entry-last{border-top:1px solid #ddd;padding-bottom:.6rem}.notifications-entry ._cutted{cursor:pointer}.notifications-entry ._cutted .notifications-entry-description-start:after{content:'...'}.notifications-entry-title{color:#ef672f;display:block;font-size:1.1rem;font-weight:700;margin-bottom:.7rem;margin-right:1em}.notifications-entry-description{color:#333;font-size:1.1rem;margin-bottom:.8rem}.notifications-entry-description-end{display:none}.notifications-entry-description-end._show{display:inline}.notifications-entry-time{color:#777;font-size:1.1rem}.notifications-close{line-height:1;padding:1rem;position:absolute;right:0;top:.6rem}.notifications-close:before{color:#ccc;content:'\e620';transition:color .1s linear}.notifications-close:hover:before{color:#b3b3b3}.notifications-close:active{-ms-transform:scale(0.95);transform:scale(0.95)}.page-header-actions{padding-top:1.1rem}.page-header-hgroup{padding-right:1.5rem}.page-title{color:#333;font-size:2.8rem}.page-header{padding:1.5rem 3rem}.menu-wrapper{display:inline-block;position:relative;width:8.8rem;z-index:700}.menu-wrapper:before{background-color:#373330;bottom:0;content:'';left:0;position:fixed;top:0;width:8.8rem;z-index:699}.menu-wrapper._fixed{left:0;position:fixed;top:0}.menu-wrapper._fixed~.page-wrapper{margin-left:8.8rem}.menu-wrapper .logo{display:block;height:8.8rem;padding:2.4rem 0 2.2rem;position:relative;text-align:center;z-index:700}._keyfocus .menu-wrapper .logo:focus{background-color:#4a4542;box-shadow:none}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a{background-color:#373330}._keyfocus .menu-wrapper .logo:focus+.admin__menu .level-0:first-child>a:after{display:none}.menu-wrapper .logo:hover .logo-img{-webkit-filter:brightness(1.1);filter:brightness(1.1)}.menu-wrapper .logo:active .logo-img{-ms-transform:scale(0.95);transform:scale(0.95)}.menu-wrapper .logo .logo-img{height:4.2rem;transition:-webkit-filter .2s linear,filter .2s linear,transform .1s linear;width:3.5rem}.abs-menu-separator,.admin__menu .item-partners>a:after,.admin__menu .level-0:first-child>a:after{background-color:#736963;content:'';display:block;height:1px;left:0;margin-left:16%;position:absolute;top:0;width:68%}.admin__menu li{display:block}.admin__menu .level-0:first-child>a{position:relative}.admin__menu .level-0._active>a,.admin__menu .level-0:hover>a{color:#f7f3eb}.admin__menu .level-0._active>a{background-color:#524d49}.admin__menu .level-0:hover>a{background-color:#4a4542}.admin__menu .level-0>a{color:#aaa6a0;display:block;font-size:1rem;letter-spacing:.025em;min-height:6.2rem;padding:1.2rem .5rem .5rem;position:relative;text-align:center;text-decoration:none;text-transform:uppercase;transition:background-color .1s linear;word-wrap:break-word;z-index:700}.admin__menu .level-0>a:focus{box-shadow:none}.admin__menu .level-0>a:before{content:'\e63a';display:block;font-size:2.2rem;height:2.2rem}.admin__menu .level-0>.submenu{background-color:#4a4542;box-shadow:0 0 3px #000;left:100%;min-height:calc(8.8rem + 2rem + 100%);padding:2rem 0 0;position:absolute;top:0;-ms-transform:translateX(-100%);transform:translateX(-100%);transition-duration:.3s;transition-property:transform,visibility;transition-timing-function:ease-in-out;visibility:hidden;z-index:697}.ie10 .admin__menu .level-0>.submenu,.ie11 .admin__menu .level-0>.submenu{height:100%}.admin__menu .level-0._show>.submenu{-ms-transform:translateX(0);transform:translateX(0);visibility:visible;z-index:698}.admin__menu .level-1{margin-left:1.5rem;margin-right:1.5rem}.admin__menu [class*=level-]:not(.level-0) a{display:block;padding:1.25rem 1.5rem}.admin__menu [class*=level-]:not(.level-0) a:hover{background-color:#403934}.admin__menu [class*=level-]:not(.level-0) a:active{background-color:#322c29;padding-bottom:1.15rem;padding-top:1.35rem}.admin__menu .submenu li{min-width:23.8rem}.admin__menu .submenu a{color:#fcfcfc;transition:background-color .1s linear}.admin__menu .submenu a:focus,.admin__menu .submenu a:hover{box-shadow:none;text-decoration:none}._keyfocus .admin__menu .submenu a:focus{background-color:#403934}._keyfocus .admin__menu .submenu a:active{background-color:#322c29}.admin__menu .submenu .parent{margin-bottom:4.5rem}.admin__menu .submenu .parent .submenu-group-title{color:#a79d95;display:block;font-size:1.6rem;font-weight:600;margin-bottom:.7rem;padding:1.25rem 1.5rem;pointer-events:none}.admin__menu .submenu .column{display:table-cell}.admin__menu .submenu-title{color:#fff;display:block;font-size:2.2rem;font-weight:600;margin-bottom:4.2rem;margin-left:3rem;margin-right:5.8rem}.admin__menu .submenu-sub-title{color:#fff;display:block;font-size:1.2rem;margin:-3.8rem 5.8rem 3.8rem 3rem}.admin__menu .action-close{padding:2.4rem 2.8rem;position:absolute;right:0;top:0}.admin__menu .action-close:before{color:#a79d95;font-size:1.7rem}.admin__menu .action-close:hover:before{color:#fff}.admin__menu .item-dashboard>a:before{content:'\e604';font-size:1.8rem;padding-top:.4rem}.admin__menu .item-sales>a:before{content:'\e60b'}.admin__menu .item-catalog>a:before{content:'\e608'}.admin__menu .item-customer>a:before{content:'\e603';font-size:2.6rem;position:relative;top:-.4rem}.admin__menu .item-marketing>a:before{content:'\e609';font-size:2rem;padding-top:.2rem}.admin__menu .item-content>a:before{content:'\e602';font-size:2.4rem;position:relative;top:-.2rem}.admin__menu .item-report>a:before{content:'\e60a'}.admin__menu .item-stores>a:before{content:'\e60d';font-size:1.9rem;padding-top:.3rem}.admin__menu .item-system>a:before{content:'\e610'}.admin__menu .item-partners._active>a:after,.admin__menu .item-system._current+.item-partners>a:after{display:none}.admin__menu .item-partners>a{padding-bottom:1rem}.admin__menu .item-partners>a:before{content:'\e612'}.admin__menu .level-0>.submenu>ul>.level-1:only-of-type>.submenu-group-title,.admin__menu .submenu .column:only-of-type .submenu-group-title{display:none}.admin__menu-overlay{bottom:0;left:0;position:fixed;right:0;top:0;z-index:697}.store-switcher{color:#333;float:left;font-size:1.3rem;margin-top:.7rem}.store-switcher .admin__action-dropdown{background-color:#f8f8f8;margin-left:.5em}.store-switcher .dropdown{display:inline-block;position:relative}.store-switcher .dropdown:after,.store-switcher .dropdown:before{content:'';display:table}.store-switcher .dropdown:after{clear:both}.store-switcher .dropdown .action.toggle{cursor:pointer;display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e607';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle:active:after,.store-switcher .dropdown .action.toggle:hover:after{color:#333}.store-switcher .dropdown .action.toggle.active{display:inline-block;text-decoration:none}.store-switcher .dropdown .action.toggle.active:after{-webkit-font-smoothing:antialiased;font-size:22px;line-height:2;color:#333;content:'\e618';font-family:icons-blank-theme;margin:0;vertical-align:top;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.store-switcher .dropdown .action.toggle.active:active:after,.store-switcher .dropdown .action.toggle.active:hover:after{color:#333}.store-switcher .dropdown .dropdown-menu{margin:4px 0 0;padding:0;list-style:none;background:#fff;border:1px solid #aaa6a0;min-width:19.5rem;z-index:100;box-sizing:border-box;display:none;position:absolute;top:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5)}.store-switcher .dropdown .dropdown-menu li{margin:0;padding:0}.store-switcher .dropdown .dropdown-menu li:hover{background:0 0;cursor:pointer}.store-switcher .dropdown.active{overflow:visible}.store-switcher .dropdown.active .dropdown-menu{display:block}.store-switcher .dropdown-menu{left:0;margin-top:.5em;max-height:250px;overflow-y:auto;padding-top:.25em}.store-switcher .dropdown-menu li{border:0;cursor:default}.store-switcher .dropdown-menu li:hover{cursor:default}.store-switcher .dropdown-menu li a,.store-switcher .dropdown-menu li span{color:#333;display:block;padding:.5rem 1.3rem}.store-switcher .dropdown-menu li a{text-decoration:none}.store-switcher .dropdown-menu li a:hover{background:#e9e9e9}.store-switcher .dropdown-menu li span{color:#adadad;cursor:default}.store-switcher .dropdown-menu li.current span{background:#eee;color:#333}.store-switcher .dropdown-menu .store-switcher-store a,.store-switcher .dropdown-menu .store-switcher-store span{padding-left:2.6rem}.store-switcher .dropdown-menu .store-switcher-store-view a,.store-switcher .dropdown-menu .store-switcher-store-view span{padding-left:3.9rem}.store-switcher .dropdown-menu .dropdown-toolbar{border-top:1px solid #ebebeb;margin-top:1rem}.store-switcher .dropdown-menu .dropdown-toolbar a:before{content:'\e610';margin-right:.25em;position:relative;top:1px}.store-switcher-label{font-weight:700}.store-switcher-alt{display:inline-block;position:relative}.store-switcher-alt.active .dropdown-menu{display:block}.store-switcher-alt .dropdown-menu{margin-top:2px;white-space:nowrap}.store-switcher-alt .dropdown-menu ul{list-style:none;margin:0;padding:0}.store-switcher-alt strong{color:#a79d95;display:block;font-size:14px;font-weight:500;line-height:1.333;padding:5px 10px}.store-switcher-alt .store-selected{color:#676056;cursor:pointer;font-size:12px;font-weight:400;line-height:1.333}.store-switcher-alt .store-selected:after{-webkit-font-smoothing:antialiased;color:#afadac;content:'\e02c';font-style:normal;font-weight:400;margin:0 0 0 3px;speak:none;vertical-align:text-top}.store-switcher-alt .store-switcher-store,.store-switcher-alt .store-switcher-website{padding:0}.store-switcher-alt .store-switcher-store:hover,.store-switcher-alt .store-switcher-website:hover{background:0 0}.store-switcher-alt .manage-stores,.store-switcher-alt .store-switcher-all,.store-switcher-alt .store-switcher-store-view{padding:0}.store-switcher-alt .manage-stores>a,.store-switcher-alt .store-switcher-all>a{color:#676056;display:block;font-size:12px;padding:8px 15px;text-decoration:none}.store-switcher-website{margin:5px 0 0}.store-switcher-website>strong{padding-left:13px}.store-switcher-store{margin:1px 0 0}.store-switcher-store>strong{padding-left:20px}.store-switcher-store>ul{margin-top:1px}.store-switcher-store-view:first-child{border-top:1px solid #e5e5e5}.store-switcher-store-view>a{color:#333;display:block;font-size:13px;padding:5px 15px 5px 24px;text-decoration:none}.store-view:not(.store-switcher){float:left}.store-view .store-switcher-label{display:inline-block;margin-top:1rem}.tooltip{margin-left:.5em}.tooltip .help a,.tooltip .help span{cursor:pointer;display:inline-block;height:22px;position:relative;vertical-align:middle;width:22px;z-index:2}.tooltip .help a:before,.tooltip .help span:before{color:#333;content:'\e633';font-size:1.7rem}.tooltip .help a:hover{text-decoration:none}.tooltip .tooltip-content{background:#000;border-radius:3px;color:#fff;display:none;margin-left:-19px;margin-top:10px;max-width:200px;padding:4px 8px;position:absolute;text-shadow:none;z-index:20}.tooltip .tooltip-content:before{border-bottom:5px solid #000;border-left:5px solid transparent;border-right:5px solid transparent;content:'';height:0;left:20px;opacity:.8;position:absolute;top:-5px;width:0}.tooltip .tooltip-content.loading{position:absolute}.tooltip .tooltip-content.loading:before{border-bottom-color:rgba(0,0,0,.3)}.tooltip:hover>.tooltip-content{display:block}.page-actions._fixed,.page-main-actions:not(._hidden){background:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;padding:1.5rem}.page-main-actions{margin:0 0 3rem}.page-main-actions._hidden .store-switcher{display:none}.page-main-actions._hidden .page-actions-placeholder{min-height:50px}.page-actions{float:right}.page-main-actions .page-actions._fixed{left:8.8rem;position:fixed;right:0;top:0;z-index:501}.page-main-actions .page-actions._fixed .page-actions-inner:before{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:#333;content:attr(data-title);float:left;font-size:2.8rem;margin-top:.3rem;max-width:50%}.page-actions .page-actions-buttons>button,.page-actions>button{float:right;margin-left:1.3rem}.page-actions .page-actions-buttons>button.action-back,.page-actions .page-actions-buttons>button.back,.page-actions>button.action-back,.page-actions>button.back{float:left;-ms-flex-order:-1;order:-1}.page-actions .page-actions-buttons>button.action-back:before,.page-actions .page-actions-buttons>button.back:before,.page-actions>button.action-back:before,.page-actions>button.back:before{content:'\e626';margin-right:.5em;position:relative;top:1px}.page-actions .page-actions-buttons>button.action-primary,.page-actions .page-actions-buttons>button.primary,.page-actions>button.action-primary,.page-actions>button.primary{-ms-flex-order:2;order:2}.page-actions .page-actions-buttons>button.save:not(.primary),.page-actions>button.save:not(.primary){-ms-flex-order:1;order:1}.page-actions .page-actions-buttons>button.delete,.page-actions>button.delete{-ms-flex-order:-1;order:-1}.page-actions .actions-split{float:right;margin-left:1.3rem;-ms-flex-order:2;order:2}.page-actions .actions-split .dropdown-menu .item{display:block}.page-actions-buttons{float:right;-ms-flex-pack:end;justify-content:flex-end;display:-ms-flexbox;display:flex}.customer-index-edit .page-actions-buttons{background-color:transparent}.admin__page-nav{background:#f1f1f1;border:1px solid #e3e3e3}.admin__page-nav._collapsed:first-child{border-bottom:none}.admin__page-nav._collapsed._show{border-bottom:1px solid #e3e3e3}.admin__page-nav._collapsed._show ._collapsible{background:#f1f1f1}.admin__page-nav._collapsed._show ._collapsible:after{content:'\e62b'}.admin__page-nav._collapsed._show ._collapsible+.admin__page-nav-items{display:block}.admin__page-nav._collapsed._hide .admin__page-nav-title-messages,.admin__page-nav._collapsed._hide .admin__page-nav-title-messages ._active{display:inline-block}.admin__page-nav+._collapsed{border-bottom:none;border-top:none}.admin__page-nav-title{border-bottom:1px solid #e3e3e3;color:#303030;display:block;font-size:1.4rem;line-height:1.2;margin:0 0 -1px;padding:1.8rem 1.5rem;position:relative;text-transform:uppercase}.admin__page-nav-title._collapsible{background:#fff;cursor:pointer;margin:0;padding-right:3.5rem;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-title._collapsible+.admin__page-nav-items{display:none;margin-top:-1px}.admin__page-nav-title._collapsible:after{content:'\e628';font-size:1.3rem;font-weight:700;position:absolute;right:1.8rem;top:2rem}.admin__page-nav-title._collapsible:hover{background:#f1f1f1}.admin__page-nav-title._collapsible:last-child{margin:0 0 -1px}.admin__page-nav-title strong{font-weight:700}.admin__page-nav-title .admin__page-nav-title-messages{display:none}.admin__page-nav-items{list-style-type:none;margin:0;padding:1rem 0 1.3rem}.admin__page-nav-item{border-left:3px solid transparent;margin-left:.7rem;padding:0;position:relative;transition:border-color .1s ease-out,background-color .1s ease-out}.admin__page-nav-item:hover{border-color:#e4e4e4}.admin__page-nav-item:hover .admin__page-nav-link{background:#e4e4e4;color:#303030;text-decoration:none}.admin__page-nav-item._active,.admin__page-nav-item.ui-state-active{border-color:#eb5202}.admin__page-nav-item._active .admin__page-nav-link,.admin__page-nav-item.ui-state-active .admin__page-nav-link{background:#fff;border-color:#e3e3e3;border-right:1px solid #fff;color:#303030;margin-right:-1px;font-weight:600}.admin__page-nav-item._loading:before,.admin__page-nav-item.ui-tabs-loading:before{display:none}.admin__page-nav-item._loading .admin__page-nav-item-message-loader,.admin__page-nav-item.ui-tabs-loading .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-link{border:1px solid transparent;border-width:1px 0;color:#303030;display:block;font-weight:500;line-height:1.2;margin:0 0 -1px;padding:2rem 4rem 2rem 1rem;transition:border-color .1s ease-out,background-color .1s ease-out;word-wrap:break-word}.admin__page-nav-item-messages{display:inline-block}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-size:1.4rem;font-weight:400;left:-1rem;line-height:1.36;padding:1.5rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after,.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}.admin__page-nav-item-messages .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf;margin-top:1px}.admin__page-nav-item-message-loader{display:none;margin-top:-1rem;position:absolute;right:0;top:50%}.admin__page-nav-item-message-loader .spinner{font-size:2rem;margin-right:1.5rem}._loading>.admin__page-nav-item-messages .admin__page-nav-item-message-loader{display:inline-block}.admin__page-nav-item-message{position:relative}.admin__page-nav-item-message:hover{z-index:500}.admin__page-nav-item-message:hover .admin__page-nav-item-message-tooltip{display:block}.admin__page-nav-item-message._changed,.admin__page-nav-item-message._error{display:none}.admin__page-nav-item-message .admin__page-nav-item-message-icon{display:inline-block;font-size:1.4rem;padding-left:.8em;vertical-align:baseline}.admin__page-nav-item-message .admin__page-nav-item-message-icon:after{color:#666;content:'\e631'}._changed:not(._error)>.admin__page-nav-item-messages ._changed{display:inline-block}._error .admin__page-nav-item-message-icon:after{color:#eb5202;content:'\e623'}._error>.admin__page-nav-item-messages ._error{display:inline-block}._error>.admin__page-nav-item-messages ._error .spinner{font-size:2rem;margin-right:1.5rem}._error .admin__page-nav-item-message-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:3.7rem;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;left:-1rem;line-height:1.36;padding:2rem;position:absolute;text-transform:none;width:27rem;word-break:normal;z-index:2}._error .admin__page-nav-item-message-tooltip:after,._error .admin__page-nav-item-message-tooltip:before{border:15px solid transparent;height:0;width:0;border-top-color:#f1f1f1;content:'';display:block;left:2rem;position:absolute;top:100%;z-index:3}._error .admin__page-nav-item-message-tooltip:after{border-top-color:#f1f1f1;margin-top:-1px;z-index:4}._error .admin__page-nav-item-message-tooltip:before{border-top-color:#bfbfbf}.admin__data-grid-wrap-static .data-grid{box-sizing:border-box}.admin__data-grid-wrap-static .data-grid thead{color:#333}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td{background-color:#f5f5f5}.admin__data-grid-wrap-static .data-grid tr:nth-child(even) td._dragging{background-color:rgba(245,245,245,.95)}.admin__data-grid-wrap-static .data-grid ul{margin-left:1rem;padding-left:1rem}.admin__data-grid-wrap-static .admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-wrap-static .admin__data-grid-loading-mask .grid-loader{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-filters-actions-wrap{float:right}.data-grid-search-control-wrap{float:left;max-width:45.5rem;position:relative;width:35%}.data-grid-search-control-wrap :-ms-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-webkit-input-placeholder{font-style:italic}.data-grid-search-control-wrap ::-moz-placeholder{font-style:italic}.data-grid-search-control-wrap .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:.6rem 2rem .2rem;position:absolute;right:0;top:1px}.data-grid-search-control-wrap .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.data-grid-search-control-wrap .action-submit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.data-grid-search-control-wrap .action-submit:hover:before{color:#1a1a1a}._keyfocus .data-grid-search-control-wrap .action-submit:focus{box-shadow:0 0 0 1px #008bdb}.data-grid-search-control-wrap .action-submit:before{content:'\e60c';font-size:2rem;transition:color .1s linear}.data-grid-search-control-wrap .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.data-grid-search-control-wrap .abs-action-menu .action-submenu,.data-grid-search-control-wrap .abs-action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .action-menu,.data-grid-search-control-wrap .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu,.data-grid-search-control-wrap .actions-split .action-menu .action-submenu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu,.data-grid-search-control-wrap .actions-split .dropdown-menu .action-submenu .action-submenu{max-height:19.25rem;overflow-y:auto;z-index:398}.data-grid-search-control-wrap .action-menu-item._selected{background-color:#e0f6fe}.data-grid-search-control-wrap .data-grid-search-label{display:none}.data-grid-search-control{padding-right:6rem;width:100%}.data-grid-filters-action-wrap{float:left;padding-left:2rem}.data-grid-filters-action-wrap .action-default{font-size:1.3rem;margin-bottom:1rem;padding-left:1.7rem;padding-right:2.1rem;padding-top:.7rem}.data-grid-filters-action-wrap .action-default._active{background-color:#fff;border-bottom-color:#fff;border-right-color:#ccc;font-weight:600;margin:-.1rem 0 0;padding-bottom:1.6rem;padding-top:.8rem;position:relative;z-index:281}.data-grid-filters-action-wrap .action-default._active:after{background-color:#eb5202;bottom:100%;content:'';height:3px;left:-1px;position:absolute;right:-1px}.data-grid-filters-action-wrap .action-default:before{color:#333;content:'\e605';font-size:1.8rem;margin-right:.4rem;position:relative;top:-1px;vertical-align:top}.data-grid-filters-action-wrap .filters-active{display:none}.admin__action-grid-select .admin__control-select{margin:-.5rem .5rem 0 0;padding-bottom:.6rem;padding-top:.6rem}.admin__data-grid-filters-wrap{opacity:0;visibility:hidden;clear:both;font-size:1.3rem;transition:opacity .3s ease}.admin__data-grid-filters-wrap._show{opacity:1;visibility:visible;border-bottom:1px solid #ccc;border-top:1px solid #ccc;margin-bottom:.7rem;padding:3.6rem 0 3rem;position:relative;top:-1px;z-index:280}.admin__data-grid-filters-wrap._show .admin__data-grid-filters,.admin__data-grid-filters-wrap._show .admin__data-grid-filters-footer{display:block}.admin__data-grid-filters-wrap .admin__form-field-label,.admin__data-grid-filters-wrap .admin__form-field-legend{display:block;font-weight:700;margin:0 0 .3rem;text-align:left}.admin__data-grid-filters-wrap .admin__form-field{display:inline-block;margin-bottom:2em;margin-left:0;padding-left:2rem;padding-right:2rem;vertical-align:top;width:calc(100% / 4 - 4px)}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field{display:block;float:none;margin-bottom:1.5rem;padding-left:0;padding-right:0;width:auto}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field:last-child{margin-bottom:0}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-label{border:1px solid transparent;float:left;font-weight:400;line-height:1.36;margin-bottom:0;padding-bottom:.6rem;padding-right:1em;padding-top:.6rem;width:25%}.admin__data-grid-filters-wrap .admin__form-field .admin__form-field .admin__form-field-control{margin-left:25%}.admin__data-grid-filters-wrap .admin__action-multiselect,.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text,.admin__data-grid-filters-wrap .admin__form-field-label{font-size:1.3rem}.admin__data-grid-filters-wrap .admin__control-select{height:3.2rem;padding-top:.5rem}.admin__data-grid-filters-wrap .admin__action-multiselect:before{height:3.2rem;width:3.2rem}.admin__data-grid-filters-wrap .admin__control-select,.admin__data-grid-filters-wrap .admin__control-text._has-datepicker{width:100%}.admin__data-grid-filters{display:none;margin-left:-2rem;margin-right:-2rem}.admin__filters-legend{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-filters-footer{display:none;font-size:1.4rem}.admin__data-grid-filters-footer .admin__footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-filters-footer .admin__footer-secondary-actions{float:left;width:50%}.admin__data-grid-filters-current{border-bottom:.1rem solid #ccc;border-top:.1rem solid #ccc;display:none;font-size:1.3rem;margin-bottom:.9rem;padding-bottom:.8rem;padding-top:1.1rem;width:100%}.admin__data-grid-filters-current._show{display:table;position:relative;top:-1px;z-index:3}.admin__data-grid-filters-current._show+.admin__data-grid-filters-wrap._show{margin-top:-1rem}.admin__current-filters-actions-wrap,.admin__current-filters-list-wrap,.admin__current-filters-title-wrap{display:table-cell;vertical-align:top}.admin__current-filters-title{margin-right:1em;white-space:nowrap}.admin__current-filters-list-wrap{width:100%}.admin__current-filters-list{margin-bottom:0}.admin__current-filters-list>li{display:inline-block;font-weight:600;margin:0 1rem .5rem;padding-right:2.6rem;position:relative}.admin__current-filters-list .action-remove{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;padding:0;line-height:1;position:absolute;right:0;top:1px}.admin__current-filters-list .action-remove:hover{background-color:transparent;border:none;box-shadow:none}.admin__current-filters-list .action-remove:hover:before{color:#949494}.admin__current-filters-list .action-remove:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__current-filters-list .action-remove:before{color:#adadad;content:'\e620';font-size:1.6rem;transition:color .1s linear}.admin__current-filters-list .action-remove>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__current-filters-actions-wrap .action-clear{border:none;padding-bottom:0;padding-top:0;white-space:nowrap}.admin__data-grid-pager-wrap{float:right;text-align:right}.admin__data-grid-pager{display:inline-block;margin-left:3rem}.admin__data-grid-pager .admin__control-text::-webkit-inner-spin-button,.admin__data-grid-pager .admin__control-text::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.admin__data-grid-pager .admin__control-text{-moz-appearance:textfield;text-align:center;width:4.4rem}.action-next,.action-previous{width:4.4rem}.action-next:before,.action-previous:before{font-weight:700}.action-next>span,.action-previous>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.action-previous{margin-right:2.5rem;text-indent:-.25em}.action-previous:before{content:'\e629'}.action-next{margin-left:1.5rem;text-indent:.1em}.action-next:before{content:'\e62a'}.admin__data-grid-action-bookmarks{opacity:.98}.admin__data-grid-action-bookmarks .admin__action-dropdown-text:after{left:0;right:-6px}.admin__data-grid-action-bookmarks._active{z-index:290}.admin__data-grid-action-bookmarks .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:15rem;min-width:4.9rem;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown:before{content:'\e60f'}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu{font-size:1.3rem;left:0;padding:1rem 0;right:auto}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li{padding:0 5rem 0 0;position:relative;white-space:nowrap}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action){transition:background-color .1s linear}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu>li:not(.action-dropdown-menu-action):hover{background-color:#e3e3e3}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item{max-width:23rem;min-width:18rem;white-space:normal;word-break:break-all}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit{display:none;padding-bottom:1rem;padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-edit .action-dropdown-menu-item-actions{padding-bottom:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action{padding-left:1rem;padding-top:1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action+.action-dropdown-menu-item-last{padding-top:.5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a{color:#008bdb;text-decoration:none;display:inline-block;padding-left:1.1rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-action>a:hover{color:#0fa7ff;text-decoration:underline}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-last{padding-bottom:0}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item{display:none}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._edit .action-dropdown-menu-item-edit{display:block}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu ._active .action-dropdown-menu-link{font-weight:600}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{font-size:1.3rem;min-width:15rem;width:calc(100% - 4rem)}.ie9 .admin__data-grid-action-bookmarks .admin__action-dropdown-menu .admin__control-text{width:15rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-item-actions{border-left:1px solid #fff;bottom:0;position:absolute;right:0;top:0;width:5rem}.admin__data-grid-action-bookmarks .admin__action-dropdown-menu .action-dropdown-menu-link{color:#333;display:block;text-decoration:none;padding:1rem 1rem 1rem 2.1rem}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit,.admin__data-grid-action-bookmarks .action-submit{background-color:transparent;border:none;border-radius:0;box-shadow:none;margin:0;vertical-align:top}.admin__data-grid-action-bookmarks .action-delete:hover,.admin__data-grid-action-bookmarks .action-edit:hover,.admin__data-grid-action-bookmarks .action-submit:hover{background-color:transparent;border:none;box-shadow:none}.admin__data-grid-action-bookmarks .action-delete:before,.admin__data-grid-action-bookmarks .action-edit:before,.admin__data-grid-action-bookmarks .action-submit:before{font-size:1.7rem}.admin__data-grid-action-bookmarks .action-delete>span,.admin__data-grid-action-bookmarks .action-edit>span,.admin__data-grid-action-bookmarks .action-submit>span{clip:rect(0,0,0,0);overflow:hidden;position:absolute}.admin__data-grid-action-bookmarks .action-delete,.admin__data-grid-action-bookmarks .action-edit{padding:.6rem 1.4rem}.admin__data-grid-action-bookmarks .action-delete:active,.admin__data-grid-action-bookmarks .action-edit:active{-ms-transform:scale(0.9);transform:scale(0.9)}.admin__data-grid-action-bookmarks .action-submit{padding:.6rem 1rem .6rem .8rem}.admin__data-grid-action-bookmarks .action-submit:active{position:relative;right:-1px}.admin__data-grid-action-bookmarks .action-submit:before{content:'\e625'}.admin__data-grid-action-bookmarks .action-delete:before{content:'\e630'}.admin__data-grid-action-bookmarks .action-edit{padding-top:.8rem}.admin__data-grid-action-bookmarks .action-edit:before{content:'\e631'}.admin__data-grid-action-columns._active{opacity:.98;z-index:290}.admin__data-grid-action-columns .admin__action-dropdown:before{content:'\e610';font-size:1.8rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-columns-menu{color:#303030;font-size:1.3rem;overflow:hidden;padding:2.2rem 3.5rem 1rem;z-index:1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-header{border-bottom:1px solid #d1d1d1}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-content{width:49.2rem}.admin__data-grid-action-columns-menu._overflow .admin__action-dropdown-menu-footer{border-top:1px solid #d1d1d1;padding-top:2.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-content{max-height:22.85rem;overflow-y:auto;padding-top:1.5rem;position:relative;width:47.4rem}.admin__data-grid-action-columns-menu .admin__field-option{float:left;height:1.9rem;margin-bottom:1.5rem;padding:0 1rem 0 0;width:15.8rem}.admin__data-grid-action-columns-menu .admin__field-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-header{padding-bottom:1.5rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-menu-footer{padding:1rem 0 2rem}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-main-actions{margin-left:25%;text-align:right}.admin__data-grid-action-columns-menu .admin__action-dropdown-footer-secondary-actions{float:left;margin-left:-1em}.admin__data-grid-action-export._active{opacity:.98;z-index:290}.admin__data-grid-action-export .admin__action-dropdown:before{content:'\e635';font-size:1.7rem;left:.3rem;margin-right:.7rem;vertical-align:top}.admin__data-grid-action-export-menu{padding-left:2rem;padding-right:2rem;padding-top:1rem}.admin__data-grid-action-export-menu .admin__action-dropdown-footer-main-actions{padding-bottom:2rem;padding-top:2.5rem;white-space:nowrap}.sticky-header{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:8.8rem;margin-top:-1px;padding:.5rem 3rem 0;position:fixed;right:0;top:77px;z-index:398}.sticky-header .admin__data-grid-wrap{margin-bottom:0;overflow-x:visible;padding-bottom:0}.sticky-header .admin__data-grid-header-row{position:relative;text-align:right}.sticky-header .admin__data-grid-header-row:last-child{margin:0}.sticky-header .admin__data-grid-actions-wrap,.sticky-header .admin__data-grid-filters-wrap,.sticky-header .admin__data-grid-pager-wrap,.sticky-header .data-grid-filters-actions-wrap,.sticky-header .data-grid-search-control-wrap{display:inline-block;float:none;vertical-align:top}.sticky-header .action-select-wrap{float:left;margin-right:1.5rem;width:16.66666667%}.sticky-header .admin__control-support-text{float:left}.sticky-header .data-grid-search-control-wrap{margin:-.5rem 0 0 1.1rem;width:auto}.sticky-header .data-grid-search-control-wrap .data-grid-search-label{box-sizing:border-box;cursor:pointer;display:block;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;position:relative;text-align:center}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:before{color:#333;content:'\e60c';font-size:2rem;transition:color .1s linear}.sticky-header .data-grid-search-control-wrap .data-grid-search-label:hover:before{color:#000}.sticky-header .data-grid-search-control-wrap .data-grid-search-label span{display:none}.sticky-header .data-grid-filters-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-left:0;position:relative}.sticky-header .data-grid-filters-actions-wrap .action-default{background-color:transparent;border:1px solid transparent;box-sizing:border-box;min-width:3.8rem;padding:1.2rem .6rem 1.7rem;text-align:center;transition:all .15s ease}.sticky-header .data-grid-filters-actions-wrap .action-default span{display:none}.sticky-header .data-grid-filters-actions-wrap .action-default:before{margin:0}.sticky-header .data-grid-filters-actions-wrap .action-default._active{background-color:#fff;border-color:#adadad #adadad #fff;box-shadow:1px 1px 5px rgba(0,0,0,.5);z-index:210}.sticky-header .data-grid-filters-actions-wrap .action-default._active:after{background-color:#fff;content:'';height:6px;left:-2px;position:absolute;right:-6px;top:100%}.sticky-header .data-grid-filters-action-wrap{padding:0}.sticky-header .admin__data-grid-filters-wrap{background-color:#fff;border:1px solid #adadad;box-shadow:0 5px 5px 0 rgba(0,0,0,.25);left:0;padding-left:3.5rem;padding-right:3.5rem;position:absolute;top:100%;width:100%;z-index:209}.sticky-header .admin__data-grid-filters-current+.admin__data-grid-filters-wrap._show{margin-top:-6px}.sticky-header .filters-active{background-color:#e04f00;border-radius:10px;color:#fff;display:block;font-size:1.4rem;font-weight:700;padding:.1rem .7rem;position:absolute;right:-7px;top:0;z-index:211}.sticky-header .filters-active:empty{padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-actions-wrap{margin:-.5rem 0 0 1.1rem;padding-right:.3rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown{background-color:transparent;box-sizing:border-box;min-width:3.8rem;padding-left:.6rem;padding-right:.6rem;text-align:center}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown .admin__action-dropdown-text{display:inline-block;max-width:0;min-width:0;overflow:hidden}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:before{margin:0}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap{margin-right:1.1rem}.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after,.sticky-header .admin__data-grid-actions-wrap .admin__action-dropdown:after{display:none}.sticky-header .admin__data-grid-actions-wrap ._active .admin__action-dropdown{background-color:#fff}.sticky-header .admin__data-grid-action-bookmarks .admin__action-dropdown:before{position:relative;top:-3px}.sticky-header .admin__data-grid-filters-current{border-bottom:0;border-top:0;margin-bottom:0;padding-bottom:0;padding-top:0}.sticky-header .admin__data-grid-pager .admin__control-text,.sticky-header .admin__data-grid-pager-wrap .admin__control-support-text,.sticky-header .data-grid-search-control-wrap .action-submit,.sticky-header .data-grid-search-control-wrap .data-grid-search-control{display:none}.sticky-header .action-next{margin:0}.sticky-header .data-grid{margin-bottom:-1px}.data-grid-cap-left,.data-grid-cap-right{background-color:#f8f8f8;bottom:-2px;position:absolute;top:6rem;width:3rem;z-index:201}.data-grid-cap-left{left:0}.admin__data-grid-header{font-size:1.4rem}.admin__data-grid-header-row+.admin__data-grid-header-row{margin-top:1.1rem}.admin__data-grid-header-row:last-child{margin-bottom:0}.admin__data-grid-header-row .action-select-wrap{display:block}.admin__data-grid-header-row .action-select{width:100%}.admin__data-grid-actions-wrap{float:right;margin-left:1.1rem;margin-top:-.5rem;text-align:right}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap{position:relative;text-align:left;vertical-align:middle}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._hide+.admin__action-dropdown-wrap:after,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:first-child:after{display:none}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown,.admin__data-grid-actions-wrap .admin__action-dropdown-wrap._active .admin__action-dropdown-menu{border-color:#adadad}.admin__data-grid-actions-wrap .admin__action-dropdown-wrap:after{border-left:1px solid #ccc;content:'';height:3.2rem;left:0;position:absolute;top:.5rem;z-index:3}.admin__data-grid-actions-wrap .admin__action-dropdown{padding-bottom:1.7rem;padding-top:1.2rem}.admin__data-grid-actions-wrap .admin__action-dropdown:after{margin-top:-.4rem}.admin__data-grid-outer-wrap{min-height:8rem;position:relative}.admin__data-grid-wrap{margin-bottom:2rem;max-width:100%;overflow-x:auto;padding-bottom:1rem;padding-top:2rem}.admin__data-grid-loading-mask{background:rgba(255,255,255,.5);bottom:0;left:0;position:absolute;right:0;top:0;z-index:399}.admin__data-grid-loading-mask .spinner{font-size:4rem;left:50%;margin-left:-2rem;margin-top:-2rem;position:absolute;top:50%}.ie9 .admin__data-grid-loading-mask .spinner{background:url(../images/loader-2.gif) 50% 50% no-repeat;bottom:0;height:149px;left:0;margin:auto;position:absolute;right:0;top:0;width:218px}.data-grid-cell-content{display:inline-block;overflow:hidden;width:100%}body._in-resize{cursor:col-resize;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body._in-resize *,body._in-resize .data-grid-th,body._in-resize .data-grid-th._draggable,body._in-resize .data-grid-th._sortable{cursor:col-resize!important}._layout-fixed{table-layout:fixed}.data-grid{border:none;font-size:1.3rem;margin-bottom:0;width:100%}.data-grid:not(._dragging-copy) ._odd-row td._dragging{background-color:#d0d0d0}.data-grid:not(._dragging-copy) ._dragging{background-color:#d9d9d9;color:rgba(48,48,48,.95)}.data-grid:not(._dragging-copy) ._dragging a{color:rgba(0,139,219,.95)}.data-grid:not(._dragging-copy) ._dragging a:hover{color:rgba(15,167,255,.95)}.data-grid._dragged{outline:#007bdb solid 1px}.data-grid thead{background-color:transparent}.data-grid tfoot th{padding:1rem}.data-grid tr._odd-row td{background-color:#f5f5f5}.data-grid tr._odd-row td._update-status-active{background:#89e1ff}.data-grid tr._odd-row td._update-status-upcoming{background:#b7ee63}.data-grid tr:hover td._update-status-active,.data-grid tr:hover td._update-status-upcoming{background-color:#e5f7fe}.data-grid tr.data-grid-tr-no-data td{font-size:1.6rem;padding:3rem;text-align:center}.data-grid tr.data-grid-tr-no-data:hover td{background-color:#fff;cursor:default}.data-grid tr:active td{background-color:#e0f6fe}.data-grid tr:hover td{background-color:#e5f7fe}.data-grid tr._dragged td{background:#d0d0d0}.data-grid tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.data-grid tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.data-grid tr:not(.data-grid-editable-row):last-child td{border-bottom:.1rem solid #d6d6d6}.data-grid tr ._clickable,.data-grid tr._clickable{cursor:pointer}.data-grid tr._disabled{pointer-events:none}.data-grid td,.data-grid th{font-size:1.3rem;line-height:1.36;transition:background-color .1s linear;vertical-align:top}.data-grid td._resizing,.data-grid th._resizing{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid td._hidden,.data-grid th._hidden{display:none}.data-grid td._fit,.data-grid th._fit{width:1%}.data-grid td{background-color:#fff;border-left:.1rem dashed #d6d6d6;border-right:.1rem dashed #d6d6d6;color:#303030;padding:1rem}.data-grid td:first-child{border-left-style:solid}.data-grid td:last-child{border-right-style:solid}.data-grid td .action-select-wrap{position:static}.data-grid td .action-select{color:#008bdb;text-decoration:none;background-color:transparent;border:none;font-size:1.3rem;padding:0 3rem 0 0;position:relative}.data-grid td .action-select:hover{color:#0fa7ff;text-decoration:underline}.data-grid td .action-select:hover:after{border-color:#0fa7ff transparent transparent}.data-grid td .action-select:after{border-color:#008bdb transparent transparent;margin:.6rem 0 0 .7rem;right:auto;top:auto}.data-grid td .action-select:before{display:none}.data-grid td .abs-action-menu .action-submenu,.data-grid td .abs-action-menu .action-submenu .action-submenu,.data-grid td .action-menu,.data-grid td .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu,.data-grid td .actions-split .action-menu .action-submenu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu,.data-grid td .actions-split .dropdown-menu .action-submenu .action-submenu{left:auto;min-width:10rem;right:0;text-align:left;top:auto;z-index:1}.data-grid td._update-status-active{background:#bceeff}.data-grid td._update-status-upcoming{background:#ccf391}.data-grid th{background-color:#514943;border:.1rem solid #8a837f;border-left-color:transparent;color:#fff;font-weight:600;padding:0;text-align:left}.data-grid th:first-child{border-left-color:#8a837f}.data-grid th._dragover-left{box-shadow:inset 3px 0 0 0 #fff;z-index:2}.data-grid th._dragover-right{box-shadow:inset -3px 0 0 0 #fff}.data-grid .shadow-div{cursor:col-resize;height:100%;margin-right:-5px;position:absolute;right:0;top:0;width:10px}.data-grid .data-grid-th{background-clip:padding-box;color:#fff;padding:1rem;position:relative;vertical-align:middle}.data-grid .data-grid-th._resize-visible .shadow-div{cursor:auto;display:none}.data-grid .data-grid-th._draggable{cursor:grab}.data-grid .data-grid-th._sortable{cursor:pointer;transition:background-color .1s linear;z-index:1}.data-grid .data-grid-th._sortable:focus,.data-grid .data-grid-th._sortable:hover{background-color:#5f564f}.data-grid .data-grid-th._sortable:active{padding-bottom:.9rem;padding-top:1.1rem}.data-grid .data-grid-th.required>span:after{color:#f38a5e;content:'*';margin-left:.3rem}.data-grid .data-grid-checkbox-cell{overflow:hidden;padding:0;vertical-align:top;width:5.2rem}.data-grid .data-grid-checkbox-cell:hover{cursor:default}.data-grid .data-grid-thumbnail-cell{text-align:center;width:7rem}.data-grid .data-grid-thumbnail-cell img{border:1px solid #d6d6d6;width:5rem}.data-grid .data-grid-multicheck-cell{padding:1rem 1rem .9rem;text-align:center;vertical-align:middle}.data-grid .data-grid-onoff-cell{text-align:center;width:12rem}.data-grid .data-grid-actions-cell{padding-left:2rem;padding-right:2rem;text-align:center;width:1%}.data-grid._hidden{display:none}.data-grid._dragging-copy{box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;opacity:.95;position:fixed;top:0;z-index:1000}.data-grid._dragging-copy .data-grid-th{border:1px solid #007bdb;border-bottom:none}.data-grid._dragging-copy .data-grid-th,.data-grid._dragging-copy .data-grid-th._sortable{cursor:grabbing}.data-grid._dragging-copy tr:last-child td{border-bottom:1px solid #007bdb}.data-grid._dragging-copy td{border-left:1px solid #007bdb;border-right:1px solid #007bdb}.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid._dragging-copy._in-edit .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:rgba(255,251,230,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td,.data-grid._dragging-copy._in-edit .data-grid-editable-row:hover td{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:after,.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{left:0;right:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:before{background-color:rgba(255,255,255,.95)}.data-grid._dragging-copy._in-edit .data-grid-editable-row td:only-child{border-left:1px solid #007bdb;border-right:1px solid #007bdb;left:0}.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-select,.data-grid._dragging-copy._in-edit .data-grid-editable-row .admin__control-text{opacity:.5}.data-grid .data-grid-controls-row td{padding-top:1.6rem}.data-grid .data-grid-controls-row td.data-grid-checkbox-cell{padding-top:.6rem}.data-grid .data-grid-controls-row td [class*=admin__control-],.data-grid .data-grid-controls-row td button{margin-top:-1.7rem}.data-grid._in-edit tr:hover td{background-color:#e6e6e6}.data-grid._in-edit ._odd-row.data-grid-editable-row td,.data-grid._in-edit ._odd-row.data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit ._odd-row td,.data-grid._in-edit ._odd-row:hover td{background-color:#dcdcdc}.data-grid._in-edit .data-grid-editable-row-actions td,.data-grid._in-edit .data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid._in-edit td{background-color:#e6e6e6;pointer-events:none}.data-grid._in-edit .data-grid-checkbox-cell{pointer-events:auto}.data-grid._in-edit .data-grid-editable-row{border:.1rem solid #adadad;border-bottom-color:#c2c2c2}.data-grid._in-edit .data-grid-editable-row:hover td{background-color:#fff}.data-grid._in-edit .data-grid-editable-row td{background-color:#fff;border-bottom-color:#fff;border-left-style:hidden;border-right-style:hidden;border-top-color:#fff;pointer-events:auto;vertical-align:middle}.data-grid._in-edit .data-grid-editable-row td:first-child{border-left-color:#adadad;border-left-style:solid}.data-grid._in-edit .data-grid-editable-row td:first-child:after,.data-grid._in-edit .data-grid-editable-row td:first-child:before{left:0}.data-grid._in-edit .data-grid-editable-row td:last-child{border-right-color:#adadad;border-right-style:solid;left:-.1rem}.data-grid._in-edit .data-grid-editable-row td:last-child:after,.data-grid._in-edit .data-grid-editable-row td:last-child:before{right:0}.data-grid._in-edit .data-grid-editable-row .admin__control-select,.data-grid._in-edit .data-grid-editable-row .admin__control-text{width:100%}.data-grid._in-edit .data-grid-bulk-edit-panel td{vertical-align:bottom}.data-grid .data-grid-editable-row td{border-left-color:#fff;border-left-style:solid;position:relative;z-index:1}.data-grid .data-grid-editable-row td:after{bottom:0;box-shadow:0 5px 5px rgba(0,0,0,.25);content:'';height:.9rem;left:0;margin-top:-1rem;position:absolute;right:0}.data-grid .data-grid-editable-row td:before{background-color:#fff;bottom:0;content:'';height:1rem;left:-10px;position:absolute;right:-10px;z-index:1}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td,.data-grid .data-grid-editable-row.data-grid-editable-row-actions:hover td{background-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:first-child{border-left-color:#fff;border-right-color:#fff}.data-grid .data-grid-editable-row.data-grid-editable-row-actions td:last-child{left:0}.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel td:before,.data-grid .data-grid-editable-row.data-grid-bulk-edit-panel:hover td{background-color:#fffbe6}.data-grid .data-grid-editable-row-actions{left:50%;margin-left:-12.5rem;margin-top:-2px;position:absolute;text-align:center}.data-grid .data-grid-editable-row-actions td{width:25rem}.data-grid .data-grid-editable-row-actions [class*=action-]{min-width:9rem}.data-grid .data-grid-draggable-row-cell{width:1%}.data-grid .data-grid-draggable-row-cell .draggable-handle{padding:0}.data-grid-th._sortable._ascend,.data-grid-th._sortable._descend{padding-right:2.7rem}.data-grid-th._sortable._ascend:before,.data-grid-th._sortable._descend:before{margin-top:-1em;position:absolute;right:1rem;top:50%}.data-grid-th._sortable._ascend:before{content:'\2193'}.data-grid-th._sortable._descend:before{content:'\2191'}.data-grid-checkbox-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:right}.data-grid-checkbox-cell-inner:hover{cursor:pointer}.data-grid-state-cell-inner{display:block;padding:1.1rem 1.8rem .9rem;text-align:center}.data-grid-state-cell-inner>span{display:inline-block;font-style:italic;padding:.6rem 0}.data-grid-row-parent._active>td .data-grid-checkbox-cell-inner:before{content:'\e62b'}.data-grid-row-parent>td .data-grid-checkbox-cell-inner{padding-left:3.7rem;position:relative}.data-grid-row-parent>td .data-grid-checkbox-cell-inner:before{content:'\e628';font-size:1rem;font-weight:700;left:1.35rem;position:absolute;top:1.6rem}.data-grid-th._col-xs{width:1%}.data-grid-info-panel{box-shadow:0 0 5px rgba(0,0,0,.5);margin:2rem .1rem -2rem}.data-grid-info-panel .messages{overflow:hidden}.data-grid-info-panel .messages .message{margin:1rem}.data-grid-info-panel .messages .message:last-child{margin-bottom:1rem}.data-grid-info-panel-actions{padding:1rem;text-align:right}.data-grid-editable-row .admin__field-control{position:relative}.data-grid-editable-row .admin__field-control._error:after{border-color:transparent #ee7d7d transparent transparent;border-style:solid;border-width:0 12px 12px 0;content:'';position:absolute;right:0;top:0}.data-grid-editable-row .admin__field-control._error .admin__control-text{border-color:#ee7d7d}.data-grid-editable-row .admin__field-control._focus:after{display:none}.data-grid-editable-row .admin__field-error{bottom:100%;box-shadow:1px 1px 5px rgba(0,0,0,.5);left:0;margin:0 auto 1.5rem;max-width:32rem;position:absolute;right:0}.data-grid-editable-row .admin__field-error:after,.data-grid-editable-row .admin__field-error:before{border-style:solid;content:'';left:50%;position:absolute;top:100%}.data-grid-editable-row .admin__field-error:after{border-color:#fffbbb transparent transparent;border-width:10px 10px 0;margin-left:-10px;z-index:1}.data-grid-editable-row .admin__field-error:before{border-color:#ee7d7d transparent transparent;border-width:11px 12px 0;margin-left:-12px}.data-grid-bulk-edit-panel .admin__field-label-vertical{display:block;font-size:1.2rem;margin-bottom:.5rem;text-align:left}.data-grid-row-changed{cursor:default;display:block;opacity:.5;position:relative;width:100%;z-index:1}.data-grid-row-changed:after{content:'\e631';display:inline-block}.data-grid-row-changed .data-grid-row-changed-tooltip{background:#f1f1f1;border:1px solid #f1f1f1;border-radius:1px;bottom:100%;box-shadow:0 3px 9px 0 rgba(0,0,0,.3);display:none;font-weight:400;line-height:1.36;margin-bottom:1.5rem;padding:1rem;position:absolute;right:-1rem;text-transform:none;width:27rem;word-break:normal;z-index:2}.data-grid-row-changed._changed{opacity:1;z-index:3}.data-grid-row-changed._changed:hover .data-grid-row-changed-tooltip{display:block}.data-grid-row-changed._changed:hover:before{background:#f1f1f1;border:1px solid #f1f1f1;bottom:100%;box-shadow:4px 4px 3px -1px rgba(0,0,0,.15);content:'';display:block;height:1.6rem;left:50%;margin:0 0 .7rem -.8rem;position:absolute;-ms-transform:rotate(45deg);transform:rotate(45deg);width:1.6rem;z-index:3}.ie9 .data-grid-row-changed._changed:hover:before{display:none}.admin__data-grid-outer-wrap .data-grid-checkbox-cell{overflow:hidden}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner{position:relative}.admin__data-grid-outer-wrap .data-grid-checkbox-cell-inner:before{bottom:0;content:'';height:500%;left:0;position:absolute;right:0;top:0}.admin__data-grid-wrap-static .data-grid-checkbox-cell:hover{cursor:pointer}.admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:1.1rem 1.8rem .9rem;padding:0}.adminhtml-cms-hierarchy-index .admin__data-grid-wrap-static .data-grid-actions-cell:first-child{padding:0}.adminhtml-export-index .admin__data-grid-wrap-static .data-grid-checkbox-cell-inner{margin:0;padding:1.1rem 1.8rem 1.9rem}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before,.admin__control-file-label:before,.admin__control-multiselect,.admin__control-select,.admin__control-text,.admin__control-textarea,.selectmenu{-webkit-appearance:none;background-color:#fff;border:1px solid #adadad;border-radius:1px;box-shadow:none;color:#303030;font-size:1.4rem;font-weight:400;height:auto;line-height:1.36;padding:.6rem 1rem;transition:border-color .1s linear;vertical-align:baseline;width:auto}.admin__control-addon [class*=admin__control-][class]:hover~[class*=admin__addon-]:last-child:before,.admin__control-multiselect:hover,.admin__control-select:hover,.admin__control-text:hover,.admin__control-textarea:hover,.selectmenu:hover,.selectmenu:hover .selectmenu-toggle:before{border-color:#878787}.admin__control-addon [class*=admin__control-][class]:focus~[class*=admin__addon-]:last-child:before,.admin__control-file:active+.admin__control-file-label:before,.admin__control-file:focus+.admin__control-file-label:before,.admin__control-multiselect:focus,.admin__control-select:focus,.admin__control-text:focus,.admin__control-textarea:focus,.selectmenu._focus,.selectmenu._focus .selectmenu-toggle:before{border-color:#007bdb;box-shadow:none;outline:0}.admin__control-addon [class*=admin__control-][class][disabled]~[class*=admin__addon-]:last-child:before,.admin__control-file[disabled]+.admin__control-file-label:before,.admin__control-multiselect[disabled],.admin__control-select[disabled],.admin__control-text[disabled],.admin__control-textarea[disabled]{background-color:#e9e9e9;border-color:#adadad;color:#303030;cursor:not-allowed;opacity:.5}.admin__field-row[class]>.admin__field-control,.admin__fieldset>.admin__field.admin__field-wide[class]>.admin__field-control{clear:left;float:none;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label{display:block;line-height:1.4rem;margin-bottom:.86rem;margin-top:-.14rem;text-align:left;width:auto}.admin__field-row[class]:not(.admin__field-option)>.admin__field-label:before,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)>.admin__field-label:before{display:none}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span{padding-left:1.5rem}.admin__field-row[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__field-row[class]:not(.admin__field-option).required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option)._required>.admin__field-label span:after,.admin__fieldset>.admin__field.admin__field-wide[class]:not(.admin__field-option).required>.admin__field-label span:after{left:0;margin-left:30px}.admin__legend{font-size:1.8rem;font-weight:600;margin-bottom:3rem}.admin__control-checkbox,.admin__control-radio{cursor:pointer;opacity:.01;overflow:hidden;position:absolute;vertical-align:top}.admin__control-checkbox:after,.admin__control-radio:after{display:none}.admin__control-checkbox+label,.admin__control-radio+label{cursor:pointer;display:inline-block}.admin__control-checkbox+label:before,.admin__control-radio+label:before{background-color:#fff;border:1px solid #adadad;color:transparent;float:left;height:1.6rem;text-align:center;vertical-align:top;width:1.6rem}.admin__control-checkbox+.admin__field-label,.admin__control-radio+.admin__field-label{padding-left:2.6rem}.admin__control-checkbox+.admin__field-label:before,.admin__control-radio+.admin__field-label:before{margin:1px 1rem 0 -2.6rem}.admin__control-checkbox:checked+label:before,.admin__control-radio:checked+label:before{color:#514943}.admin__control-checkbox.disabled+label,.admin__control-checkbox[disabled]+label,.admin__control-radio.disabled+label,.admin__control-radio[disabled]+label{color:#303030;cursor:default;opacity:.5}.admin__control-checkbox.disabled+label:before,.admin__control-checkbox[disabled]+label:before,.admin__control-radio.disabled+label:before,.admin__control-radio[disabled]+label:before{background-color:#e9e9e9;border-color:#adadad;cursor:default}._keyfocus .admin__control-checkbox:not(.disabled):focus+label:before,._keyfocus .admin__control-checkbox:not([disabled]):focus+label:before,._keyfocus .admin__control-radio:not(.disabled):focus+label:before,._keyfocus .admin__control-radio:not([disabled]):focus+label:before{border-color:#007bdb}.admin__control-checkbox:not(.disabled):hover+label:before,.admin__control-checkbox:not([disabled]):hover+label:before,.admin__control-radio:not(.disabled):hover+label:before,.admin__control-radio:not([disabled]):hover+label:before{border-color:#878787}.admin__control-radio+label:before{border-radius:1.6rem;content:'';transition:border-color .1s linear,color .1s ease-in}.admin__control-radio.admin__control-radio+label:before{line-height:140%}.admin__control-radio:checked+label{position:relative}.admin__control-radio:checked+label:after{background-color:#514943;border-radius:50%;content:'';height:10px;left:3px;position:absolute;top:4px;width:10px}.admin__control-radio:checked:not(.disabled):hover,.admin__control-radio:checked:not(.disabled):hover+label,.admin__control-radio:checked:not([disabled]):hover,.admin__control-radio:checked:not([disabled]):hover+label{cursor:default}.admin__control-radio:checked:not(.disabled):hover+label:before,.admin__control-radio:checked:not([disabled]):hover+label:before{border-color:#adadad}.admin__control-checkbox+label:before{border-radius:1px;content:'';font-size:0;transition:font-size .1s ease-out,color .1s ease-out,border-color .1s linear}.admin__control-checkbox:checked+label:before{content:'\e62d';font-size:1.1rem;line-height:125%}.admin__control-checkbox:not(:checked)._indeterminate+label:before,.admin__control-checkbox:not(:checked):indeterminate+label:before{color:#514943;content:'-';font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:700}input[type=checkbox].admin__control-checkbox,input[type=radio].admin__control-checkbox{margin:0;position:absolute}.admin__control-text{min-width:4rem}.admin__control-select{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none;background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#adadad,#adadad);background-position:calc(100% - 12px) -34px,100%,calc(100% - 3.2rem) 0;background-size:auto,3.2rem 100%,1px 100%;background-repeat:no-repeat;max-width:100%;min-width:8.5rem;padding-bottom:.5rem;padding-right:4.4rem;padding-top:.5rem;transition:border-color .1s linear}.admin__control-select:hover{border-color:#878787;cursor:pointer}.admin__control-select:focus{background-image:url(../images/arrows-bg.svg),linear-gradient(#e3e3e3,#e3e3e3),linear-gradient(#007bdb,#007bdb);background-position:calc(100% - 12px) 13px,100%,calc(100% - 3.2rem) 0;border-color:#007bdb}.admin__control-select::-ms-expand{display:none}.ie9 .admin__control-select{background-image:none;padding-right:1rem}option:empty{display:none}.admin__control-multiselect{height:auto;max-width:100%;min-width:15rem;overflow:auto;padding:0;resize:both}.admin__control-multiselect optgroup,.admin__control-multiselect option{padding:.5rem 1rem}.admin__control-file-wrapper{display:inline-block;padding:.5rem 1rem;position:relative;z-index:1}.admin__control-file-label:before{content:'';left:0;position:absolute;top:0;width:100%;z-index:0}.admin__control-file{background:0 0;border:0;padding-top:.7rem;position:relative;width:auto;z-index:1}.admin__control-support-text{border:1px solid transparent;display:inline-block;font-size:1.4rem;line-height:1.36;padding-bottom:.6rem;padding-top:.6rem}.admin__control-support-text+[class*=admin__control-],[class*=admin__control-]+.admin__control-support-text{margin-left:.7rem}.admin__control-service{float:left;margin:.8rem 0 0 3rem}.admin__control-textarea{height:8.48rem;line-height:1.18;padding-top:.8rem;resize:vertical}.admin__control-addon{-ms-flex-direction:row;flex-direction:row;display:inline-flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;position:relative;width:100%;z-index:1}.admin__control-addon>[class*=admin__addon-],.admin__control-addon>[class*=admin__control-]{-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0;position:relative;z-index:1}.admin__control-addon .admin__control-select{width:auto}.admin__control-addon .admin__control-text{margin:.1rem;padding:.5rem .9rem;width:100%}.admin__control-addon [class*=admin__control-][class]{appearence:none;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-order:1;order:1;-ms-flex-negative:1;flex-shrink:1;background-color:transparent;border-color:transparent;box-shadow:none;vertical-align:top}.admin__control-addon [class*=admin__control-][class]+[class*=admin__control-]{border-left-color:#adadad}.admin__control-addon [class*=admin__control-][class] :focus{box-shadow:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child{padding-left:1rem;position:static!important;z-index:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child>*{position:relative;vertical-align:top;z-index:1}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:empty{padding:0}.admin__control-addon [class*=admin__control-][class]~[class*=admin__addon-]:last-child:before{bottom:0;box-sizing:border-box;content:'';left:0;position:absolute;top:0;width:100%;z-index:-1}.admin__addon-prefix,.admin__addon-suffix{border:0;box-sizing:border-box;color:#858585;display:inline-block;font-size:1.4rem;font-weight:400;height:3.2rem;line-height:3.2rem;padding:0}.admin__addon-suffix{-ms-flex-order:3;order:3}.admin__addon-suffix:last-child{padding-right:1rem}.admin__addon-prefix{-ms-flex-order:0;order:0}.ie9 .admin__control-addon:after{clear:both;content:'';display:block;height:0;overflow:hidden}.ie9 .admin__addon{min-width:0;overflow:hidden;text-align:right;white-space:nowrap;width:auto}.ie9 .admin__addon [class*=admin__control-]{display:inline}.ie9 .admin__addon-prefix{float:left}.ie9 .admin__addon-suffix{float:right}.admin__control-collapsible{width:100%}.admin__control-collapsible ._dragged .admin__collapsible-block-wrapper .admin__collapsible-title{background:#d0d0d0}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before,.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{background:#008bdb;content:'';display:block;height:3px;left:0;position:absolute;right:0}.admin__control-collapsible ._dragover-top .admin__collapsible-block-wrapper:before{top:-3px}.admin__control-collapsible ._dragover-bottom .admin__collapsible-block-wrapper:before{bottom:-3px}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper{border:0;margin:0;position:relative}.admin__control-collapsible .admin__collapsible-block-wrapper.fieldset-wrapper .fieldset-wrapper-title{background:#f8f8f8;border:2px solid #ccc}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title{font-size:1.4rem;font-weight:400;line-height:1;padding:1.6rem 4rem 1.6rem 3.8rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .admin__collapsible-title:before{left:1rem;right:auto;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding:0;position:absolute;right:1rem;top:1.4rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete:before{content:'\e630';font-size:2rem}.admin__control-collapsible .admin__collapsible-block-wrapper .fieldset-wrapper-title .action-delete>span{display:none}.admin__control-collapsible .admin__collapsible-content{background-color:#fff;margin-bottom:1rem}.admin__control-collapsible .admin__collapsible-content>.fieldset-wrapper{border:1px solid #ccc;margin-top:-1px;padding:1rem}.admin__control-collapsible .admin__collapsible-content .admin__fieldset{padding:0}.admin__control-collapsible .admin__collapsible-content .admin__field:last-child{margin-bottom:0}.admin__control-table-wrapper{max-width:100%;overflow-x:auto;overflow-y:hidden}.admin__control-table{width:100%}.admin__control-table thead{background-color:transparent}.admin__control-table tbody td{vertical-align:top}.admin__control-table tfoot th{padding-bottom:1.3rem}.admin__control-table tfoot th.validation{padding-bottom:0;padding-top:0}.admin__control-table tfoot td{border-top:1px solid #fff}.admin__control-table tfoot .admin__control-table-pagination{float:right;padding-bottom:0}.admin__control-table tfoot .action-previous{margin-right:.5rem}.admin__control-table tfoot .action-next{margin-left:.9rem}.admin__control-table tr:last-child td{border-bottom:none}.admin__control-table tr._dragover-top td{box-shadow:inset 0 3px 0 0 #008bdb}.admin__control-table tr._dragover-bottom td{box-shadow:inset 0 -3px 0 0 #008bdb}.admin__control-table tr._dragged td,.admin__control-table tr._dragged th{background:#d0d0d0}.admin__control-table td,.admin__control-table th{background-color:#efefef;border:0;border-bottom:1px solid #fff;padding:1.3rem 1rem 1.3rem 0;text-align:left;vertical-align:top}.admin__control-table td:first-child,.admin__control-table th:first-child{padding-left:1rem}.admin__control-table td>.admin__control-select,.admin__control-table td>.admin__control-text,.admin__control-table th>.admin__control-select,.admin__control-table th>.admin__control-text{width:100%}.admin__control-table td._hidden,.admin__control-table th._hidden{display:none}.admin__control-table td._fit,.admin__control-table th._fit{width:1px}.admin__control-table th{color:#303030;font-size:1.4rem;font-weight:600;vertical-align:bottom}.admin__control-table th._required span:after{color:#eb5202;content:'*'}.admin__control-table .control-table-actions-th{white-space:nowrap}.admin__control-table .control-table-actions-cell{padding-top:1.8rem;text-align:center;width:1%}.admin__control-table .control-table-options-th{text-align:center;width:10rem}.admin__control-table .control-table-options-cell{text-align:center}.admin__control-table .control-table-text{line-height:3.2rem}.admin__control-table .col-draggable{padding-top:2.2rem;width:1%}.admin__control-table .action-delete{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.admin__control-table .action-delete:hover{background-color:transparent;border-color:transparent;box-shadow:none}.admin__control-table .action-delete:before{content:'\e630';font-size:2rem}.admin__control-table .action-delete>span{display:none}.admin__control-table .draggable-handle{padding:0}.admin__control-table._dragged{outline:#007bdb solid 1px}.admin__control-table-action{background-color:#efefef;border-top:1px solid #fff;padding:1.3rem 1rem}.admin__dynamic-rows._dragged{opacity:.95;position:absolute;z-index:999}.admin__dynamic-rows.admin__control-table .admin__control-fields>.admin__field{border:0;padding:0}.admin__dynamic-rows td>.admin__field{border:0;margin:0;padding:0}.admin__control-table-pagination{padding-bottom:1rem}.admin__control-table-pagination .admin__data-grid-pager{float:right}.admin__field-tooltip{display:inline-block;margin-top:.5rem;max-width:45px;overflow:visible;vertical-align:top;width:0}.admin__field-tooltip:hover{position:relative;z-index:500}.admin__field-option .admin__field-tooltip{margin-top:.5rem}.admin__field-tooltip .admin__field-tooltip-action{margin-left:2rem;position:relative;z-index:2;display:inline-block;text-decoration:none}.admin__field-tooltip .admin__field-tooltip-action:before{-webkit-font-smoothing:antialiased;font-size:2.2rem;line-height:1;color:#514943;content:'\e633';font-family:Icons;vertical-align:middle;display:inline-block;font-weight:400;overflow:hidden;speak:none;text-align:center}.admin__field-tooltip .admin__control-text:focus+.admin__field-tooltip-content,.admin__field-tooltip:hover .admin__field-tooltip-content{display:block}.admin__field-tooltip .admin__field-tooltip-content{bottom:3.8rem;display:none;right:-2.3rem}.admin__field-tooltip .admin__field-tooltip-content:after,.admin__field-tooltip .admin__field-tooltip-content:before{border:1.6rem solid transparent;height:0;width:0;border-top-color:#afadac;content:'';display:block;position:absolute;right:2rem;top:100%;z-index:3}.admin__field-tooltip .admin__field-tooltip-content:after{border-top-color:#fffbbb;margin-top:-1px;z-index:4}.abs-admin__field-tooltip-content,.admin__field-tooltip .admin__field-tooltip-content{box-shadow:0 2px 8px 0 rgba(0,0,0,.3);background:#fffbbb;border:1px solid #afadac;border-radius:1px;padding:1.5rem 2.5rem;position:absolute;width:32rem;z-index:1}.admin__field-fallback-reset{font-size:1.25rem;white-space:nowrap;width:30px}.admin__field-fallback-reset>span{margin-left:.5rem;position:relative}.admin__field-fallback-reset:active{-ms-transform:scale(0.98);transform:scale(0.98)}.admin__field-fallback-reset:before{transition:color .1s linear;content:'\e642';font-size:1.3rem;margin-left:.5rem}.admin__field-fallback-reset:hover{cursor:pointer;text-decoration:none}.admin__field-fallback-reset:focus{background:0 0}.abs-field-size-x-small,.abs-field-sizes.admin__field-x-small>.admin__field-control,.admin__field.admin__field-x-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-x-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-x-small>.admin__field-control{width:8rem}.abs-field-size-small,.abs-field-sizes.admin__field-small>.admin__field-control,.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control,.admin__field.admin__field-small>.admin__field-control,.admin__fieldset>.admin__field.admin__field-small>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-small>.admin__field-control{width:15rem}.abs-field-size-medium,.abs-field-sizes.admin__field-medium>.admin__field-control,.admin__field.admin__field-medium>.admin__field-control,.admin__fieldset>.admin__field.admin__field-medium>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-medium>.admin__field-control{width:34rem}.abs-field-size-large,.abs-field-sizes.admin__field-large>.admin__field-control,.admin__field.admin__field-large>.admin__field-control,.admin__fieldset>.admin__field.admin__field-large>.admin__field-control,[class*=admin__control-grouped]>.admin__field.admin__field-large>.admin__field-control{width:64rem}.abs-field-no-label,.admin__field-group-additional,.admin__field-no-label,.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-control{margin-left:calc((100%) * .25 + 30px)}.admin__fieldset{border:0;margin:0;min-width:0;padding:0}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title{padding-left:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section>.fieldset-wrapper-title strong{font-size:1.7rem;font-weight:600}.admin__fieldset .fieldset-wrapper.admin__fieldset-section .admin__fieldset-wrapper-content>.admin__fieldset{padding-top:1rem}.admin__fieldset .fieldset-wrapper.admin__fieldset-section:last-child .admin__fieldset-wrapper-content>.admin__fieldset{padding-bottom:0}.admin__fieldset>.admin__field{border:0;margin:0 0 0 -30px;padding:0}.admin__fieldset>.admin__field:after{clear:both;content:'';display:table}.admin__fieldset>.admin__field>.admin__field-control{width:calc((100%) * .5 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.admin__fieldset>.admin__field.admin__field-no-label>.admin__field-label{display:none}.admin__fieldset>.admin__field+.admin__field._empty._no-header{margin-top:-3rem}.admin__fieldset-product-websites{position:relative;z-index:300}.admin__fieldset-note{margin-bottom:2rem}.admin__form-field{border:0;margin:0;padding:0}.admin__field-control .admin__control-text,.admin__field-control .admin__control-textarea,.admin__form-field-control .admin__control-text,.admin__form-field-control .admin__control-textarea{width:100%}.admin__field-label{color:#303030;cursor:pointer;margin:0;text-align:right}.admin__field-label+br{display:none}.admin__field:not(.admin__field-option)>.admin__field-label{font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:600;line-height:3.2rem;padding:0;white-space:nowrap}.admin__field:not(.admin__field-option)>.admin__field-label:before{opacity:0;visibility:hidden;content:'.';margin-left:-7px;overflow:hidden}.admin__field:not(.admin__field-option)>.admin__field-label span{display:inline-block;line-height:1.2;vertical-align:middle;white-space:normal}.admin__field:not(.admin__field-option)>.admin__field-label span[data-config-scope]{position:relative}._required>.admin__field-label>span:after,.required>.admin__field-label>span:after{color:#eb5202;content:'*';display:inline-block;font-size:1.6rem;font-weight:500;line-height:1;margin-left:10px;margin-top:.2rem;position:absolute;z-index:1}._disabled>.admin__field-label{color:#999;cursor:default}.admin__field{margin-bottom:0}.admin__field+.admin__field{margin-top:1.5rem}.admin__field:not(.admin__field-option)~.admin__field-option{margin-top:.5rem}.admin__field.admin__field-option~.admin__field-option{margin-top:.9rem}.admin__field~.admin__field-option:last-child{margin-bottom:.8rem}.admin__fieldset>.admin__field{margin-bottom:3rem;position:relative}.admin__field legend.admin__field-label{opacity:0}.admin__field[data-config-scope]:before{color:gray;content:attr(data-config-scope);display:inline-block;font-size:1.2rem;left:calc((100%) * .75 - 30px);line-height:3.2rem;margin-left:60px;position:absolute;width:calc((100%) * .25 - 30px)}.admin__field-control .admin__field[data-config-scope]:nth-child(n+2):before{content:''}.admin__field._error .admin__field-control [class*=admin__addon-]:before,.admin__field._error .admin__field-control [class*=admin__control-] [class*=admin__addon-]:before,.admin__field._error .admin__field-control>[class*=admin__control-]{border-color:#e22626}.admin__field._disabled,.admin__field._disabled:hover{box-shadow:inherit;cursor:inherit;opacity:1;outline:inherit}.admin__field._hidden{display:none}.admin__field-control+.admin__field-control{margin-top:1.5rem}.admin__field-control._with-tooltip>.admin__control-addon,.admin__field-control._with-tooltip>.admin__control-select,.admin__field-control._with-tooltip>.admin__control-text,.admin__field-control._with-tooltip>.admin__control-textarea,.admin__field-control._with-tooltip>.admin__field-option{max-width:calc(100% - 45px - 4px)}.admin__field-control._with-tooltip .admin__field-tooltip{width:auto}.admin__field-control._with-tooltip .admin__field-option{display:inline-block}.admin__field-control._with-reset>.admin__control-addon,.admin__field-control._with-reset>.admin__control-text,.admin__field-control._with-reset>.admin__control-textarea{width:calc(100% - 30px - .5rem - 4px)}.admin__field-control._with-reset .admin__field-fallback-reset{margin-left:.5rem;margin-top:1rem;vertical-align:top}.admin__field-control._with-reset._with-tooltip>.admin__control-addon,.admin__field-control._with-reset._with-tooltip>.admin__control-text,.admin__field-control._with-reset._with-tooltip>.admin__control-textarea{width:calc(100% - 30px - .5rem - 45px - 8px)}.admin__fieldset>.admin__field-collapsible{margin-bottom:0}.admin__fieldset>.admin__field-collapsible .admin__field-control{border-top:1px solid #ccc;display:block;font-size:1.7rem;font-weight:700;padding:1.7rem 0;width:calc(97%)}.admin__fieldset>.admin__field-collapsible .admin__field-option{padding-top:0}.admin__field-collapsible+div{margin-top:2.5rem}.admin__field-collapsible .admin__control-radio+label:before{height:1.8rem;width:1.8rem}.admin__field-collapsible .admin__control-radio:checked+label:after{left:4px;top:5px}.admin__field-error{background:#fffbbb;border:1px solid #ee7d7d;box-sizing:border-box;color:#555;display:block;font-size:1.2rem;font-weight:400;line-height:1.2;margin:.2rem 0 0;padding:.8rem 1rem .9rem}.admin__field-note{color:#303030;font-size:1.2rem;margin:10px 0 0;padding:0}.admin__additional-info{padding-top:1rem}.admin__field-option{padding-top:.7rem}.admin__field-option .admin__field-label{text-align:left}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2),.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1){display:inline-block}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option{display:inline-block;margin-left:41px;margin-top:0}.admin__field-control>.admin__field-option:nth-child(1):nth-last-child(2)+.admin__field-option:before,.admin__field-control>.admin__field-option:nth-child(2):nth-last-child(1)+.admin__field-option:before{background:#cacaca;content:'';display:inline-block;height:20px;margin-left:-20px;position:absolute;width:1px}.admin__field-value{display:inline-block;padding-top:.7rem}.admin__field-service{padding-top:1rem}.admin__control-fields>.admin__field:first-child,[class*=admin__control-grouped]>.admin__field:first-child{position:static}.admin__control-fields>.admin__field:first-child>.admin__field-label,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label{width:calc((100%) * .25 - 30px);float:left;margin-left:30px;background:#fff;cursor:pointer;left:0;position:absolute;top:0}.admin__control-fields>.admin__field:first-child>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field:first-child>.admin__field-label span:before{display:block}.admin__control-fields>.admin__field._disabled>.admin__field-label,[class*=admin__control-grouped]>.admin__field._disabled>.admin__field-label{cursor:default}.admin__control-fields>.admin__field>.admin__field-label span:before,[class*=admin__control-grouped]>.admin__field>.admin__field-label span:before{display:none}.admin__control-fields .admin__field-label~.admin__field-control{width:100%}.admin__control-fields .admin__field-option{padding-top:0}[class*=admin__control-grouped]{box-sizing:border-box;display:table;width:100%}[class*=admin__control-grouped]>.admin__field{display:table-cell;vertical-align:top}[class*=admin__control-grouped]>.admin__field>.admin__field-control{float:none;width:100%}[class*=admin__control-grouped]>.admin__field.admin__field-default,[class*=admin__control-grouped]>.admin__field.admin__field-large,[class*=admin__control-grouped]>.admin__field.admin__field-medium,[class*=admin__control-grouped]>.admin__field.admin__field-small,[class*=admin__control-grouped]>.admin__field.admin__field-x-small{width:1px}[class*=admin__control-grouped]>.admin__field.admin__field-default+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-large+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-medium+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-small+.admin__field:last-child,[class*=admin__control-grouped]>.admin__field.admin__field-x-small+.admin__field:last-child{width:auto}[class*=admin__control-grouped]>.admin__field:nth-child(n+2){padding-left:20px}.admin__control-group-equal{table-layout:fixed}.admin__control-group-equal>.admin__field{width:50%}.admin__field-control-group{margin-top:.8rem}.admin__field-control-group>.admin__field{padding:0}.admin__control-grouped-date>.admin__field-date{white-space:nowrap;width:1px}.admin__control-grouped-date>.admin__field-date.admin__field>.admin__field-control{float:left;position:relative}.admin__control-grouped-date>.admin__field-date+.admin__field:last-child{width:auto}.admin__control-grouped-date>.admin__field-date+.admin__field-date>.admin__field-label{float:left;padding-right:20px}.admin__control-grouped-date .ui-datepicker-trigger{left:100%;top:0}.admin__field-group-columns.admin__field-control.admin__control-grouped{width:calc((100%) * 1 - 30px);float:left;margin-left:30px}.admin__field-group-columns>.admin__field:first-child>.admin__field-label{float:none;margin:0;opacity:1;position:static;text-align:left}.admin__field-group-columns .admin__control-select{width:100%}.admin__field-group-additional{clear:both}.admin__field-group-additional .action-advanced{margin-top:1rem}.admin__field-group-additional .action-secondary{width:100%}.admin__field-group-show-label{white-space:nowrap}.admin__field-group-show-label>.admin__field-control,.admin__field-group-show-label>.admin__field-label{display:inline-block;vertical-align:top}.admin__field-group-show-label>.admin__field-label{margin-right:20px}.admin__field-complex{margin:1rem 0 3rem;padding-left:1rem}.admin__field:not(._hidden)+.admin__field-complex{margin-top:3rem}.admin__field-complex .admin__field-complex-title{clear:both;color:#303030;font-size:1.7rem;font-weight:600;letter-spacing:.025em;margin-bottom:1rem}.admin__field-complex .admin__field-complex-elements{float:right;max-width:40%}.admin__field-complex .admin__field-complex-elements button{margin-left:1rem}.admin__field-complex .admin__field-complex-content{max-width:60%;overflow:hidden}.admin__field-complex .admin__field-complex-text{margin-left:-1rem}.admin__field-complex+.admin__field._empty._no-header{margin-top:-3rem}.admin__legend{float:left;position:static;width:100%}.admin__legend+br{clear:left;display:block;height:0;overflow:hidden}.message{margin-bottom:3rem}.message-icon-top:before{margin-top:0;top:1.8rem}.nav{background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;border-top:1px solid #e3e3e3;display:none;margin-bottom:3rem;padding:2.2rem 1.5rem 0 0}.nav .btn-group,.nav-bar-outer-actions{float:right;margin-bottom:1.7rem}.nav .btn-group .btn-wrap,.nav-bar-outer-actions .btn-wrap{float:right;margin-left:.5rem;margin-right:.5rem}.nav .btn-group .btn-wrap .btn,.nav-bar-outer-actions .btn-wrap .btn{padding-left:.5rem;padding-right:.5rem}.nav-bar-outer-actions{margin-top:-10.6rem;padding-right:1.5rem}.btn-wrap-try-again{width:9.5rem}.btn-wrap-next,.btn-wrap-prev{width:8.5rem}.nav-bar{counter-reset:i;float:left;margin:0 1rem 1.7rem 0;padding:0;position:relative;white-space:nowrap}.nav-bar:before{background-color:#d4d4d4;background-repeat:repeat-x;background-image:linear-gradient(to bottom,#d1d1d1 0,#d4d4d4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d1d1d1', endColorstr='#d4d4d4', GradientType=0);border-bottom:1px solid #d9d9d9;border-top:1px solid #bfbfbf;content:'';height:1rem;left:5.15rem;position:absolute;right:5.15rem;top:.7rem}.nav-bar>li{display:inline-block;font-size:0;position:relative;vertical-align:top;width:10.3rem}.nav-bar>li:first-child:after{display:none}.nav-bar>li:after{background-color:#514943;content:'';height:.5rem;left:calc(-50% + .25rem);position:absolute;right:calc(50% + .7rem);top:.9rem}.nav-bar>li.disabled:before,.nav-bar>li.ui-state-disabled:before{bottom:0;content:'';left:0;position:absolute;right:0;top:0;z-index:1}.nav-bar>li.active~li:after,.nav-bar>li.ui-state-active~li:after{display:none}.nav-bar>li.active~li a:after,.nav-bar>li.ui-state-active~li a:after{background-color:transparent;border-color:transparent;color:#a6a6a6}.nav-bar>li.active a,.nav-bar>li.ui-state-active a{color:#000}.nav-bar>li.active a:hover,.nav-bar>li.ui-state-active a:hover{cursor:default}.nav-bar>li.active a:after,.nav-bar>li.ui-state-active a:after{background-color:#fff;content:''}.nav-bar a{color:#514943;display:block;font-size:1.2rem;font-weight:600;line-height:1.2;overflow:hidden;padding:3rem .5em 0;position:relative;text-align:center;text-overflow:ellipsis}.nav-bar a:hover{text-decoration:none}.nav-bar a:after{background-color:#514943;border:.4rem solid #514943;border-radius:100%;color:#fff;content:counter(i);counter-increment:i;height:1.5rem;left:50%;line-height:.6;margin-left:-.8rem;position:absolute;right:auto;text-align:center;top:.4rem;width:1.5rem}.nav-bar a:before{background-color:#d6d6d6;border:1px solid transparent;border-bottom-color:#d9d9d9;border-radius:100%;border-top-color:#bfbfbf;content:'';height:2.3rem;left:50%;line-height:1;margin-left:-1.2rem;position:absolute;top:0;width:2.3rem}.tooltip{display:block;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1.19rem;font-weight:400;line-height:1.4;opacity:0;position:absolute;visibility:visible;z-index:10}.tooltip.in{opacity:.9}.tooltip.top{margin-top:-4px;padding:8px 0}.tooltip.right{margin-left:4px;padding:0 8px}.tooltip.bottom{margin-top:4px;padding:8px 0}.tooltip.left{margin-left:-4px;padding:0 8px}.tooltip p:last-child{margin-bottom:0}.tooltip-inner{background-color:#fff;border:1px solid #adadad;border-radius:0;box-shadow:1px 1px 1px #ccc;color:#41362f;max-width:31rem;padding:.5em 1em;text-decoration:none}.tooltip-arrow,.tooltip-arrow:after{border:solid transparent;height:0;position:absolute;width:0}.tooltip-arrow:after{content:'';position:absolute}.tooltip.top .tooltip-arrow,.tooltip.top .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:50%;margin-left:-8px}.tooltip.top-left .tooltip-arrow,.tooltip.top-left .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;margin-bottom:-8px;right:8px}.tooltip.top-right .tooltip-arrow,.tooltip.top-right .tooltip-arrow:after{border-top-color:#949494;border-width:8px 8px 0;bottom:0;left:8px;margin-bottom:-8px}.tooltip.right .tooltip-arrow,.tooltip.right .tooltip-arrow:after{border-right-color:#949494;border-width:8px 8px 8px 0;left:1px;margin-top:-8px;top:50%}.tooltip.right .tooltip-arrow:after{border-right-color:#fff;border-width:6px 7px 6px 0;margin-left:0;margin-top:-6px}.tooltip.left .tooltip-arrow,.tooltip.left .tooltip-arrow:after{border-left-color:#949494;border-width:8px 0 8px 8px;margin-top:-8px;right:0;top:50%}.tooltip.bottom .tooltip-arrow,.tooltip.bottom .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:50%;margin-left:-8px;top:0}.tooltip.bottom-left .tooltip-arrow,.tooltip.bottom-left .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;margin-top:-8px;right:8px;top:0}.tooltip.bottom-right .tooltip-arrow,.tooltip.bottom-right .tooltip-arrow:after{border-bottom-color:#949494;border-width:0 8px 8px;left:8px;margin-top:-8px;top:0}.password-strength{display:block;margin:0 -.3rem 1em;white-space:nowrap}.password-strength.password-strength-too-short .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child,.password-strength.password-strength-weak .password-strength-item:first-child+.password-strength-item{background-color:#e22626}.password-strength.password-strength-fair .password-strength-item:first-child,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-fair .password-strength-item:first-child+.password-strength-item+.password-strength-item{background-color:#ef672f}.password-strength.password-strength-good .password-strength-item:first-child,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item,.password-strength.password-strength-good .password-strength-item:first-child+.password-strength-item+.password-strength-item+.password-strength-item,.password-strength.password-strength-strong .password-strength-item{background-color:#79a22e}.password-strength .password-strength-item{background-color:#ccc;display:inline-block;font-size:0;height:1.4rem;margin-right:.3rem;width:calc(20% - .6rem)}@keyframes progress-bar-stripes{from{background-position:4rem 0}to{background-position:0 0}}.progress{background-color:#fafafa;border:1px solid #ccc;clear:left;height:3rem;margin-bottom:3rem;overflow:hidden}.progress-bar{background-color:#79a22e;color:#fff;float:left;font-size:1.19rem;height:100%;line-height:3rem;text-align:center;transition:width .6s ease;width:0}.progress-bar.active{animation:progress-bar-stripes 2s linear infinite}.progress-bar-text-description{margin-bottom:1.6rem}.progress-bar-text-progress{text-align:right}.page-columns .page-inner-sidebar{margin:0 0 3rem}.page-header{margin-bottom:2.7rem;padding-bottom:2rem;position:relative}.page-header:before{border-bottom:1px solid #e3e3e3;bottom:0;content:'';display:block;height:1px;left:3rem;position:absolute;right:3rem}.container .page-header:before{content:normal}.page-header .message{margin-bottom:1.8rem}.page-header .message+.message{margin-top:-1.5rem}.page-header .admin__action-dropdown,.page-header .search-global-input{transition:none}.container .page-header{margin-bottom:0}.page-title-wrapper{margin-top:1.1rem}.container .page-title-wrapper{background:url(../../pub/images/logo.svg) no-repeat;min-height:41px;padding:4px 0 0 45px}.admin__menu .level-0:first-child>a{margin-top:1.6rem}.admin__menu .level-0:first-child>a:after{top:-1.6rem}.admin__menu .level-0:first-child._active>a:after{display:block}.admin__menu .level-0>a{padding-bottom:1.3rem;padding-top:1.3rem}.admin__menu .level-0>a:before{margin-bottom:.7rem}.admin__menu .item-home>a:before{content:'\e611';font-size:2.3rem;padding-top:-.1rem}.admin__menu .item-component>a:before{content:'\e612'}.admin__menu .item-extension>a:before{content:'\e647'}.admin__menu .item-upgrade>a:before{content:'\e614'}.admin__menu .item-system-config>a:before{content:'\e610'}.admin__menu .item-tools>a:before{content:'\e613'}.modal-sub-title{font-size:1.7rem;font-weight:600}.modal-connect-signin .modal-inner-wrap{max-width:80rem}@keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}.ngdialog{-webkit-overflow-scrolling:touch;bottom:0;box-sizing:border-box;left:0;overflow:auto;position:fixed;right:0;top:0;z-index:999}.ngdialog *,.ngdialog:after,.ngdialog:before{box-sizing:inherit}.ngdialog.ngdialog-disabled-animation *{animation:none!important}.ngdialog.ngdialog-closing .ngdialog-content,.ngdialog.ngdialog-closing .ngdialog-overlay{-webkit-animation:ngdialog-fadeout .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadeout .5s}.ngdialog-overlay{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s;background:rgba(0,0,0,.4);bottom:0;left:0;position:fixed;right:0;top:0}.ngdialog-content{-webkit-animation:ngdialog-fadein .5s;-webkit-backface-visibility:hidden;animation:ngdialog-fadein .5s}body.ngdialog-open{overflow:hidden}.component-indicator{border-radius:50%;cursor:help;display:inline-block;height:16px;text-align:center;vertical-align:middle;width:16px}.component-indicator::after,.component-indicator::before{background:#fff;display:block;opacity:0;position:absolute;transition:opacity .2s linear .1s;visibility:hidden}.component-indicator::before{border:1px solid #adadad;border-radius:1px;box-shadow:0 0 2px rgba(0,0,0,.4);content:attr(data-label);font-size:1.2rem;margin:30px 0 0 -10px;min-width:50px;padding:4px 5px}.component-indicator::after{border-color:#999;border-style:solid;border-width:1px 0 0 1px;box-shadow:-1px -1px 1px rgba(0,0,0,.1);content:'';height:10px;margin:9px 0 0 5px;-ms-transform:rotate(45deg);transform:rotate(45deg);width:10px}.component-indicator:hover::after,.component-indicator:hover::before{opacity:1;transition:opacity .2s linear;visibility:visible}.component-indicator span{display:block;height:16px;overflow:hidden;width:16px}.component-indicator span:before{content:'';display:block;font-family:Icons;font-size:16px;height:100%;line-height:16px;width:100%}.component-indicator._on{background:#79a22e}.component-indicator._off{background:#e22626}.component-indicator._off span:before{background:#fff;height:4px;margin:8px auto 20px;width:12px}.component-indicator._info{background:0 0}.component-indicator._info span{width:21px}.component-indicator._info span:before{color:#008bdb;content:'\e648';font-family:Icons;font-size:16px}.component-indicator._tooltip{background:0 0;margin:0 0 8px 5px}.component-indicator._tooltip a{width:21px}.component-indicator._tooltip a:hover{text-decoration:none}.component-indicator._tooltip a:before{color:#514943;content:'\e633';font-family:Icons;font-size:16px}.col-manager-item-name .data-grid-data{padding-left:5px}.col-manager-item-name .ng-hide+.data-grid-data{padding-left:24px}.col-manager-item-name ._hide-dependencies,.col-manager-item-name ._show-dependencies{cursor:pointer;padding-left:24px;position:relative}.col-manager-item-name ._hide-dependencies:before,.col-manager-item-name ._show-dependencies:before{display:block;font-family:Icons;font-size:12px;left:0;position:absolute;top:1px}.col-manager-item-name ._show-dependencies:before{content:'\e62b'}.col-manager-item-name ._hide-dependencies:before{content:'\e628'}.col-manager-item-name ._no-dependencies{padding-left:24px}.product-modules-block{font-size:1.2rem;padding:15px 0 0}.col-manager-item-name .product-modules-block{padding-left:1rem}.product-modules-descriprion,.product-modules-title{font-weight:700;margin:0 0 7px}.product-modules-list{font-size:1.1rem;list-style:none;margin:0}.col-manager-item-name .product-modules-list{margin-left:15px}.col-manager-item-name .product-modules-list li{padding:0 0 0 15px;position:relative}.product-modules-list li{margin:0 0 .5rem}.product-modules-list .component-indicator{height:10px;left:0;position:absolute;top:3px;width:10px}.module-summary{white-space:nowrap}.module-summary-title{font-size:2.1rem;margin-right:1rem}.app-updater .nav{display:block;margin-bottom:3.1rem;margin-top:-2.8rem}.app-updater .nav-bar-outer-actions{margin-top:1rem;padding-right:0}.app-updater .nav-bar-outer-actions .btn-wrap-cancel{margin-right:2.6rem}.main{padding-bottom:2rem;padding-top:3rem}.menu-wrapper .logo-static{pointer-events:none}.header{display:none}.header .logo{float:left;height:4.1rem;width:3.5rem}.header-title{font-size:2.8rem;letter-spacing:.02em;line-height:1.4;margin:2.5rem 0 3.5rem 5rem}.page-title{margin-bottom:1rem}.page-sub-title{font-size:2rem}.accent-box{margin-bottom:2rem}.accent-box .btn-prime{margin-top:1.5rem}.spinner.side{float:left;font-size:2.4rem;margin-left:2rem;margin-top:-5px}.page-landing{margin:7.6% auto 0;max-width:44rem;text-align:center}.page-landing .logo{height:5.6rem;margin-bottom:2rem;width:19.2rem}.page-landing .text-version{margin-bottom:3rem}.page-landing .text-welcome{margin-bottom:6.5rem}.page-landing .text-terms{margin-bottom:2.5rem;text-align:center}.page-landing .btn-submit,.page-license .license-text{margin-bottom:2rem}.page-license .page-license-footer{text-align:right}.readiness-check-item{margin-bottom:4rem;min-height:2.5rem}.readiness-check-item .spinner{float:left;font-size:2.5rem;margin:-.4rem 0 0 1.7rem}.readiness-check-title{font-size:1.4rem;font-weight:700;margin-bottom:.1rem;margin-left:5.7rem}.readiness-check-content{margin-left:5.7rem;margin-right:22rem;position:relative}.readiness-check-content .readiness-check-title{margin-left:0}.readiness-check-content .list{margin-top:-.3rem}.readiness-check-side{left:100%;padding-left:2.4rem;position:absolute;top:0;width:22rem}.readiness-check-side .side-title{margin-bottom:0}.readiness-check-icon{float:left;margin-left:1.7rem;margin-top:.3rem}.extensions-information{margin-bottom:5rem}.extensions-information h3{font-size:1.4rem;margin-bottom:1.3rem}.extensions-information .message{margin-bottom:2.5rem}.extensions-information .message:before{margin-top:0;top:1.8rem}.extensions-information .extensions-container{padding:0 2rem}.extensions-information .list{margin-bottom:1rem}.extensions-information .list select{cursor:pointer}.extensions-information .list select:disabled{background:#ccc;cursor:default}.extensions-information .list .extension-delete{font-size:1.7rem;padding-top:0}.delete-modal-wrap{padding:0 4% 4rem}.delete-modal-wrap h3{font-size:3.4rem;display:inline-block;font-weight:300;margin:0 0 2rem;padding:.9rem 0 0;vertical-align:top}.delete-modal-wrap .actions{padding:3rem 0 0}.page-web-configuration .form-el-insider-wrap{width:auto}.page-web-configuration .form-el-insider{width:15.4rem}.page-web-configuration .form-el-insider-input .form-el-input{width:16.5rem}.customize-your-store .advanced-modules-count,.customize-your-store .advanced-modules-select{padding-left:1.5rem}.customize-your-store .customize-your-store-advanced{min-width:0}.customize-your-store .message-error:before{margin-top:0;top:1.8rem}.customize-your-store .message-error a{color:#333;text-decoration:underline}.customize-your-store .message-error .form-label:before{background:#fff}.customize-your-store .customize-database-clean p{margin-top:2.5rem}.content-install{margin-bottom:2rem}.console{border:1px solid #ccc;font-family:'Courier New',Courier,monospace;font-weight:300;height:20rem;margin:1rem 0 2rem;overflow-y:auto;padding:1.5rem 2rem 2rem;resize:vertical}.console .text-danger{color:#e22626}.console .text-success{color:#090}.console .hidden{display:none}.content-success .btn-prime{margin-top:1.5rem}.jumbo-title{font-size:3.6rem}.jumbo-title .jumbo-icon{font-size:3.8rem;margin-right:.25em;position:relative;top:.15em}.install-database-clean{margin-top:4rem}.install-database-clean .btn{margin-right:1rem}.page-sub-title{margin-bottom:2.1rem;margin-top:3rem}.multiselect-custom{max-width:71.1rem}.content-install{margin-top:3.7rem}.home-page-inner-wrap{margin:0 auto;max-width:91rem}.setup-home-title{margin-bottom:3.9rem;padding-top:1.8rem;text-align:center}.setup-home-item{background-color:#fafafa;border:1px solid #ccc;color:#333;display:block;margin-bottom:2rem;margin-left:1.3rem;margin-right:1.3rem;min-height:30rem;padding:2rem;text-align:center}.setup-home-item:hover{border-color:#8c8c8c;color:#333;text-decoration:none;transition:border-color .1s linear}.setup-home-item:active{-ms-transform:scale(0.99);transform:scale(0.99)}.setup-home-item:before{display:block;font-size:7rem;margin-bottom:3.3rem;margin-top:4rem}.setup-home-item-component:before,.setup-home-item-extension:before{content:'\e612'}.setup-home-item-module:before{content:'\e647'}.setup-home-item-upgrade:before{content:'\e614'}.setup-home-item-configuration:before{content:'\e610'}.setup-home-item-title{display:block;font-size:1.8rem;letter-spacing:.025em;margin-bottom:1rem}.setup-home-item-description{display:block}.extension-manager-wrap{border:1px solid #bbb;margin:0 0 4rem}.extension-manager-account{font-size:2.1rem;display:inline-block;font-weight:400}.extension-manager-title{font-size:3.2rem;background-color:#f8f8f8;border-bottom:1px solid #e3e3e3;color:#41362f;font-weight:600;line-height:1.2;padding:2rem}.extension-manager-content{padding:2.5rem 2rem 2rem}.extension-manager-items{list-style:none;margin:0;text-align:center}.extension-manager-items .btn{border:1px solid #adadad;display:block;margin:1rem auto 0}.extension-manager-items .item-title{font-size:2.1rem;display:inline-block;text-align:left}.extension-manager-items .item-number{font-size:4.1rem;display:inline-block;line-height:.8;margin:0 5px 1.5rem 0;vertical-align:top}.extension-manager-items .item-date{font-size:2.6rem;margin-top:1px}.extension-manager-items .item-date-title{font-size:1.5rem}.extension-manager-items .item-install{margin:0 0 2rem}.sync-login-wrap{padding:0 10% 4rem}.sync-login-wrap .legend{font-size:2.6rem;color:#eb5202;float:left;font-weight:300;line-height:1.2;margin:-1rem 0 2.5rem;position:static;width:100%}.sync-login-wrap .legend._hidden{display:none}.sync-login-wrap .login-header{font-size:3.4rem;font-weight:300;margin:0 0 2rem}.sync-login-wrap .login-header span{display:inline-block;padding:.9rem 0 0;vertical-align:top}.sync-login-wrap h4{font-size:1.4rem;margin:0 0 2rem}.sync-login-wrap .sync-login-steps{margin:0 0 2rem 1.5rem}.sync-login-wrap .sync-login-steps li{padding:0 0 0 1rem}.sync-login-wrap .form-row .form-label{display:inline-block}.sync-login-wrap .form-row .form-label.required{padding-left:1.5rem}.sync-login-wrap .form-row .form-label.required:after{left:0;position:absolute;right:auto}.sync-login-wrap .form-row{max-width:28rem}.sync-login-wrap .form-actions{display:table;margin-top:-1.3rem}.sync-login-wrap .form-actions .links{display:table-header-group}.sync-login-wrap .form-actions .actions{padding:3rem 0 0}@media all and (max-width:1047px){.admin__menu .submenu li{min-width:19.8rem}.nav{padding-bottom:5.38rem;padding-left:1.5rem;text-align:center}.nav-bar{display:inline-block;float:none;margin-right:0;vertical-align:top}.nav .btn-group,.nav-bar-outer-actions{display:inline-block;float:none;margin-top:-8.48rem;text-align:center;vertical-align:top;width:100%}.nav-bar-outer-actions{padding-right:0}.nav-bar-outer-actions .outer-actions-inner-wrap{display:inline-block}.app-updater .nav{padding-bottom:1.7rem}.app-updater .nav-bar-outer-actions{margin-top:2rem}}@media all and (min-width:768px){.page-layout-admin-2columns-left .page-columns{margin-left:-30px}.page-layout-admin-2columns-left .page-columns:after{clear:both;content:'';display:table}.page-layout-admin-2columns-left .page-columns .main-col{width:calc((100%) * .75 - 30px);float:right}.page-layout-admin-2columns-left .page-columns .side-col{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}.col-m-1,.col-m-10,.col-m-11,.col-m-12,.col-m-2,.col-m-3,.col-m-4,.col-m-5,.col-m-6,.col-m-7,.col-m-8,.col-m-9{float:left}.col-m-12{width:100%}.col-m-11{width:91.66666667%}.col-m-10{width:83.33333333%}.col-m-9{width:75%}.col-m-8{width:66.66666667%}.col-m-7{width:58.33333333%}.col-m-6{width:50%}.col-m-5{width:41.66666667%}.col-m-4{width:33.33333333%}.col-m-3{width:25%}.col-m-2{width:16.66666667%}.col-m-1{width:8.33333333%}.col-m-pull-12{right:100%}.col-m-pull-11{right:91.66666667%}.col-m-pull-10{right:83.33333333%}.col-m-pull-9{right:75%}.col-m-pull-8{right:66.66666667%}.col-m-pull-7{right:58.33333333%}.col-m-pull-6{right:50%}.col-m-pull-5{right:41.66666667%}.col-m-pull-4{right:33.33333333%}.col-m-pull-3{right:25%}.col-m-pull-2{right:16.66666667%}.col-m-pull-1{right:8.33333333%}.col-m-pull-0{right:auto}.col-m-push-12{left:100%}.col-m-push-11{left:91.66666667%}.col-m-push-10{left:83.33333333%}.col-m-push-9{left:75%}.col-m-push-8{left:66.66666667%}.col-m-push-7{left:58.33333333%}.col-m-push-6{left:50%}.col-m-push-5{left:41.66666667%}.col-m-push-4{left:33.33333333%}.col-m-push-3{left:25%}.col-m-push-2{left:16.66666667%}.col-m-push-1{left:8.33333333%}.col-m-push-0{left:auto}.col-m-offset-12{margin-left:100%}.col-m-offset-11{margin-left:91.66666667%}.col-m-offset-10{margin-left:83.33333333%}.col-m-offset-9{margin-left:75%}.col-m-offset-8{margin-left:66.66666667%}.col-m-offset-7{margin-left:58.33333333%}.col-m-offset-6{margin-left:50%}.col-m-offset-5{margin-left:41.66666667%}.col-m-offset-4{margin-left:33.33333333%}.col-m-offset-3{margin-left:25%}.col-m-offset-2{margin-left:16.66666667%}.col-m-offset-1{margin-left:8.33333333%}.col-m-offset-0{margin-left:0}.page-columns{margin-left:-30px}.page-columns:after{clear:both;content:'';display:table}.page-columns .page-inner-content{width:calc((100%) * .75 - 30px);float:right}.page-columns .page-inner-sidebar{width:calc((100%) * .25 - 30px);float:left;margin-left:30px}}@media all and (min-width:1048px){.col-l-1,.col-l-10,.col-l-11,.col-l-12,.col-l-2,.col-l-3,.col-l-4,.col-l-5,.col-l-6,.col-l-7,.col-l-8,.col-l-9{float:left}.col-l-12{width:100%}.col-l-11{width:91.66666667%}.col-l-10{width:83.33333333%}.col-l-9{width:75%}.col-l-8{width:66.66666667%}.col-l-7{width:58.33333333%}.col-l-6{width:50%}.col-l-5{width:41.66666667%}.col-l-4{width:33.33333333%}.col-l-3{width:25%}.col-l-2{width:16.66666667%}.col-l-1{width:8.33333333%}.col-l-pull-12{right:100%}.col-l-pull-11{right:91.66666667%}.col-l-pull-10{right:83.33333333%}.col-l-pull-9{right:75%}.col-l-pull-8{right:66.66666667%}.col-l-pull-7{right:58.33333333%}.col-l-pull-6{right:50%}.col-l-pull-5{right:41.66666667%}.col-l-pull-4{right:33.33333333%}.col-l-pull-3{right:25%}.col-l-pull-2{right:16.66666667%}.col-l-pull-1{right:8.33333333%}.col-l-pull-0{right:auto}.col-l-push-12{left:100%}.col-l-push-11{left:91.66666667%}.col-l-push-10{left:83.33333333%}.col-l-push-9{left:75%}.col-l-push-8{left:66.66666667%}.col-l-push-7{left:58.33333333%}.col-l-push-6{left:50%}.col-l-push-5{left:41.66666667%}.col-l-push-4{left:33.33333333%}.col-l-push-3{left:25%}.col-l-push-2{left:16.66666667%}.col-l-push-1{left:8.33333333%}.col-l-push-0{left:auto}.col-l-offset-12{margin-left:100%}.col-l-offset-11{margin-left:91.66666667%}.col-l-offset-10{margin-left:83.33333333%}.col-l-offset-9{margin-left:75%}.col-l-offset-8{margin-left:66.66666667%}.col-l-offset-7{margin-left:58.33333333%}.col-l-offset-6{margin-left:50%}.col-l-offset-5{margin-left:41.66666667%}.col-l-offset-4{margin-left:33.33333333%}.col-l-offset-3{margin-left:25%}.col-l-offset-2{margin-left:16.66666667%}.col-l-offset-1{margin-left:8.33333333%}.col-l-offset-0{margin-left:0}}@media all and (min-width:1440px){.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{float:left}.col-xl-12{width:100%}.col-xl-11{width:91.66666667%}.col-xl-10{width:83.33333333%}.col-xl-9{width:75%}.col-xl-8{width:66.66666667%}.col-xl-7{width:58.33333333%}.col-xl-6{width:50%}.col-xl-5{width:41.66666667%}.col-xl-4{width:33.33333333%}.col-xl-3{width:25%}.col-xl-2{width:16.66666667%}.col-xl-1{width:8.33333333%}.col-xl-pull-12{right:100%}.col-xl-pull-11{right:91.66666667%}.col-xl-pull-10{right:83.33333333%}.col-xl-pull-9{right:75%}.col-xl-pull-8{right:66.66666667%}.col-xl-pull-7{right:58.33333333%}.col-xl-pull-6{right:50%}.col-xl-pull-5{right:41.66666667%}.col-xl-pull-4{right:33.33333333%}.col-xl-pull-3{right:25%}.col-xl-pull-2{right:16.66666667%}.col-xl-pull-1{right:8.33333333%}.col-xl-pull-0{right:auto}.col-xl-push-12{left:100%}.col-xl-push-11{left:91.66666667%}.col-xl-push-10{left:83.33333333%}.col-xl-push-9{left:75%}.col-xl-push-8{left:66.66666667%}.col-xl-push-7{left:58.33333333%}.col-xl-push-6{left:50%}.col-xl-push-5{left:41.66666667%}.col-xl-push-4{left:33.33333333%}.col-xl-push-3{left:25%}.col-xl-push-2{left:16.66666667%}.col-xl-push-1{left:8.33333333%}.col-xl-push-0{left:auto}.col-xl-offset-12{margin-left:100%}.col-xl-offset-11{margin-left:91.66666667%}.col-xl-offset-10{margin-left:83.33333333%}.col-xl-offset-9{margin-left:75%}.col-xl-offset-8{margin-left:66.66666667%}.col-xl-offset-7{margin-left:58.33333333%}.col-xl-offset-6{margin-left:50%}.col-xl-offset-5{margin-left:41.66666667%}.col-xl-offset-4{margin-left:33.33333333%}.col-xl-offset-3{margin-left:25%}.col-xl-offset-2{margin-left:16.66666667%}.col-xl-offset-1{margin-left:8.33333333%}.col-xl-offset-0{margin-left:0}}@media all and (max-width:767px){.abs-clearer-mobile:after,.nav-bar:after{clear:both;content:'';display:table}.list-definition>dt{float:none}.list-definition>dd{margin-left:0}.form-row .form-label{text-align:left}.form-row .form-label.required:after{position:static}.nav{padding-bottom:0;padding-left:0;padding-right:0}.nav-bar-outer-actions{margin-top:0}.nav-bar{display:block;margin-bottom:0;margin-left:auto;margin-right:auto;width:30.9rem}.nav-bar:before{display:none}.nav-bar>li{float:left;min-height:9rem}.nav-bar>li:after{display:none}.nav-bar>li:nth-child(4n){clear:both}.nav-bar a{line-height:1.4}.tooltip{display:none!important}.readiness-check-content{margin-right:2rem}.readiness-check-side{padding:2rem 0;position:static}.form-el-insider,.form-el-insider-wrap,.page-web-configuration .form-el-insider-input,.page-web-configuration .form-el-insider-input .form-el-input{display:block;width:100%}}@media all and (max-width:479px){.nav-bar{width:23.175rem}.nav-bar>li{width:7.725rem}.nav .btn-group .btn-wrap-try-again,.nav-bar-outer-actions .btn-wrap-try-again{clear:both;display:block;float:none;margin-left:auto;margin-right:auto;margin-top:1rem;padding-top:1rem}} diff --git a/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php b/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php index 0148152b0eaa6..fa4c9c897e7b1 100644 --- a/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php +++ b/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php @@ -1,6 +1,6 @@ objectManagerFactory = $objectManagerFactory; $this->validator = $validator; - $this->objectManager = $objectManager; + $this->objectManager = $objectManagerProvider->get(); + parent::__construct(); } @@ -121,109 +112,116 @@ protected function configure() Options::FORCE_RUN, '-f', InputOption::VALUE_NONE, - 'If specified, then run files will be deployed in any mode.' + 'Deploy files in any mode.' ), new InputOption( Options::NO_JAVASCRIPT, null, InputOption::VALUE_NONE, - 'If specified, no JavaScript will be deployed.' + 'Do not deploy JavaScript files' ), new InputOption( Options::NO_CSS, null, InputOption::VALUE_NONE, - 'If specified, no CSS will be deployed.' + 'Do not deploy CSS files.' ), new InputOption( Options::NO_LESS, null, InputOption::VALUE_NONE, - 'If specified, no LESS will be deployed.' + 'Do not deploy LESS files.' ), new InputOption( Options::NO_IMAGES, null, InputOption::VALUE_NONE, - 'If specified, no images will be deployed.' + 'Do not deploy images.' ), new InputOption( Options::NO_FONTS, null, InputOption::VALUE_NONE, - 'If specified, no font files will be deployed.' + 'Do not deploy font files.' ), new InputOption( Options::NO_HTML, null, InputOption::VALUE_NONE, - 'If specified, no html files will be deployed.' + 'Do not deploy HTML files.' ), new InputOption( Options::NO_MISC, null, InputOption::VALUE_NONE, - 'If specified, no miscellaneous files will be deployed.' + 'Do not deploy other types of files (.md, .jbf, .csv, etc...).' ), new InputOption( Options::NO_HTML_MINIFY, null, InputOption::VALUE_NONE, - 'If specified, html will not be minified.' + 'Do not minify HTML files.' ), new InputOption( Options::THEME, '-t', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, - 'If specified, just specific theme(s) will be actually deployed.', + 'Generate static view files for only the specified themes.', ['all'] ), new InputOption( Options::EXCLUDE_THEME, null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, - 'If specified, exclude specific theme(s) from deployment.', + 'Do not generate files for the specified themes.', ['none'] ), new InputOption( Options::LANGUAGE, '-l', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, - 'List of languages you want the tool populate files for.', + 'Generate files only for the specified languages.', ['all'] ), new InputOption( Options::EXCLUDE_LANGUAGE, null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, - 'List of langiages you do not want the tool populate files for.', + 'Do not generate files for the specified languages.', ['none'] ), new InputOption( Options::AREA, '-a', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, - 'List of areas you want the tool populate files for.', + 'Generate files only for the specified areas.', ['all'] ), new InputOption( Options::EXCLUDE_AREA, null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, - 'List of areas you do not want the tool populate files for.', + 'Do not generate files for the specified areas.', ['none'] ), new InputOption( Options::JOBS_AMOUNT, '-j', InputOption::VALUE_OPTIONAL, - 'Amount of jobs to which script can be paralleled.', + 'Enable parallel processing using the specified number of jobs.', self::DEFAULT_JOBS_AMOUNT ), + new InputOption( + Options::SYMLINK_LOCALE, + null, + InputOption::VALUE_NONE, + 'Create symlinks for the files of those locales, which are passed for deployment, ' + . 'but have no customizations' + ), new InputArgument( self::LANGUAGES_ARGUMENT, InputArgument::IS_ARRAY, - 'List of languages you want the tool populate files for.' + 'Space-separated list of ISO-636 language codes for which to output static view files.' ), ]); @@ -368,14 +366,18 @@ private function getDeployableEntities($entities, $includedEntities, $excludedEn /** * {@inheritdoc} * @throws \InvalidArgumentException + * @throws LocalizedException */ protected function execute(InputInterface $input, OutputInterface $output) { if (!$input->getOption(Options::FORCE_RUN) && $this->getAppState()->getMode() !== State::MODE_PRODUCTION) { throw new LocalizedException( __( - "Deploy static content is applicable only for production mode.\n" - . "Please use command 'bin/magento deploy:mode:set production' for set up production mode." + 'NOTE: Manual static content deployment is not required in "default" and "developer" modes.' + . PHP_EOL . 'In "default" and "developer" modes static contents are being deployed ' + . 'automatically on demand.' + . PHP_EOL . 'If you still want to deploy in these modes, use -f option: ' + . "'bin/magento setup:static-content:deploy -f'" ) ); } @@ -386,28 +388,34 @@ protected function execute(InputInterface $input, OutputInterface $output) list ($deployableLanguages, $deployableAreaThemeMap, $requestedThemes) = $this->prepareDeployableEntities($filesUtil); - $output->writeln("Requested languages: " . implode(', ', $deployableLanguages)); - $output->writeln("Requested areas: " . implode(', ', array_keys($deployableAreaThemeMap))); - $output->writeln("Requested themes: " . implode(', ', $requestedThemes)); + $output->writeln('Requested languages: ' . implode(', ', $deployableLanguages)); + $output->writeln('Requested areas: ' . implode(', ', array_keys($deployableAreaThemeMap))); + $output->writeln('Requested themes: ' . implode(', ', $requestedThemes)); - $deployer = $this->objectManager->create( - \Magento\Deploy\Model\Deployer::class, + /** @var $deployManager DeployManager */ + $deployManager = $this->objectManager->create( + DeployManager::class, [ - 'filesUtil' => $filesUtil, 'output' => $output, 'options' => $this->input->getOptions(), ] ); - if ($this->isCanBeParalleled()) { - return $this->runProcessesInParallel($deployer, $deployableAreaThemeMap, $deployableLanguages); - } else { - return $this->deploy($deployer, $deployableLanguages, $deployableAreaThemeMap); + foreach ($deployableAreaThemeMap as $area => $themes) { + foreach ($deployableLanguages as $locale) { + foreach ($themes as $themePath) { + $deployManager->addPack($area, $themePath, $locale); + } + } } + + $this->mockCache(); + return $deployManager->deploy(); } /** * @param Files $filesUtil + * @throws \InvalidArgumentException * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) @@ -466,87 +474,16 @@ private function prepareDeployableEntities($filesUtil) } /** - * @param \Magento\Deploy\Model\Deployer $deployer - * @param array $deployableLanguages - * @param array $deployableAreaThemeMap - * @return int - */ - private function deploy($deployer, $deployableLanguages, $deployableAreaThemeMap) - { - return $deployer->deploy( - $this->objectManagerFactory, - $deployableLanguages, - $deployableAreaThemeMap - ); - } - - /** - * @param \Magento\Deploy\Model\Deployer $deployer - * @param array $deployableAreaThemeMap - * @param array $deployableLanguages - * @return int - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - private function runProcessesInParallel($deployer, $deployableAreaThemeMap, $deployableLanguages) - { - /** @var ProcessManager $processManager */ - $processManager = $this->objectManager->create(ProcessManager::class); - $processNumber = 0; - $processQueue = []; - foreach ($deployableAreaThemeMap as $area => &$themes) { - foreach ($themes as $theme) { - foreach ($deployableLanguages as $lang) { - $deployerFunc = function (Process $process) use ($area, $theme, $lang, $deployer) { - return $this->deploy($deployer, [$lang], [$area => [$theme]]); - }; - if ($processNumber >= $this->getProcessesAmount()) { - $processQueue[] = $deployerFunc; - } else { - $processManager->fork($deployerFunc); - } - $processNumber++; - } - } - } - $returnStatus = null; - while (count($processManager->getProcesses()) > 0) { - foreach ($processManager->getProcesses() as $process) { - if ($process->isCompleted()) { - $processManager->delete($process); - $returnStatus |= $process->getStatus(); - if ($queuedProcess = array_shift($processQueue)) { - $processManager->fork($queuedProcess); - } - if (count($processManager->getProcesses()) >= $this->getProcessesAmount()) { - break 1; - } - } - } - usleep(5000); - } - - return $returnStatus === Cli::RETURN_SUCCESS ?: Cli::RETURN_FAILURE; - } - - /** - * @return bool - */ - private function isCanBeParalleled() - { - return function_exists('pcntl_fork') && $this->getProcessesAmount() > 1; - } - - /** - * @return int + * Mock Cache class with dummy implementation + * + * @return void */ - private function getProcessesAmount() + private function mockCache() { - $jobs = (int)$this->input->getOption(Options::JOBS_AMOUNT); - if ($jobs < 1) { - throw new \InvalidArgumentException( - Options::JOBS_AMOUNT . ' argument has invalid value. It must be greater than 0' - ); - } - return $jobs; + $this->objectManager->configure([ + 'preferences' => [ + Cache::class => DummyCache::class + ] + ]); } } diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php index 65c0b090d6334..bc443379a6bd4 100644 --- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php @@ -1,6 +1,6 @@ componentRegistrar->getPaths(ComponentRegistrar::MODULE); $libraryPaths = $this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY); - $generationPath = $this->directoryList->getPath(DirectoryList::GENERATION); + $generationPath = $this->directoryList->getPath(DirectoryList::GENERATED_CODE); $this->objectManager->get(\Magento\Framework\App\Cache::class)->clean(); $compiledPathsList = [ @@ -140,17 +140,9 @@ protected function execute(InputInterface $input, OutputInterface $output) 'library' => $libraryPaths, 'generated_helpers' => $generationPath ]; - $excludedModulePaths = []; - foreach ($modulePaths as $appCodePath) { - $excludedModulePaths[] = '#^' . $appCodePath . '/Test#'; - } - $excludedLibraryPaths = []; - foreach ($libraryPaths as $libraryPath) { - $excludedLibraryPaths[] = '#^' . $libraryPath . '/([\\w]+/)?Test#'; - } $this->excludedPathsList = [ - 'application' => $excludedModulePaths, - 'framework' => $excludedLibraryPaths + 'application' => $this->getExcludedModulePaths($modulePaths), + 'framework' => $this->getExcludedLibraryPaths($libraryPaths), ]; $this->configureObjectManager($output); @@ -160,7 +152,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->cleanupFilesystem( [ DirectoryList::CACHE, - DirectoryList::DI, + DirectoryList::GENERATED_METADATA, ] ); foreach ($operations as $operationCode => $arguments) { @@ -205,6 +197,54 @@ function (OperationInterface $operation) use ($progressBar) { } } + /** + * Build list of module path regexps which should be excluded from compilation + * + * @param string[] $modulePaths + * @return string[] + */ + private function getExcludedModulePaths(array $modulePaths) + { + $modulesByBasePath = []; + foreach ($modulePaths as $modulePath) { + $moduleDir = basename($modulePath); + $vendorPath = dirname($modulePath); + $vendorDir = basename($vendorPath); + $basePath = dirname($vendorPath); + $modulesByBasePath[$basePath][$vendorDir][] = $moduleDir; + } + + $basePathsRegExps = []; + foreach ($modulesByBasePath as $basePath => $vendorPaths) { + $vendorPathsRegExps = []; + foreach ($vendorPaths as $vendorDir => $vendorModules) { + $vendorPathsRegExps[] = $vendorDir + . '/(?:' . join('|', $vendorModules) . ')'; + } + $basePathsRegExps[] = $basePath + . '/(?:' . join('|', $vendorPathsRegExps) . ')'; + } + + $excludedModulePaths = [ + '#^(?:' . join('|', $basePathsRegExps) . ')/Test#', + ]; + return $excludedModulePaths; + } + + /** + * Build list of library path regexps which should be excluded from compilation + * + * @param string[] $libraryPaths + * @return string[] + */ + private function getExcludedLibraryPaths(array $libraryPaths) + { + $excludedLibraryPaths = [ + '#^(?:' . join('|', $libraryPaths) . ')/([\\w]+/)?Test#', + ]; + return $excludedLibraryPaths; + } + /** * Delete directories by their code from "var" directory * diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php deleted file mode 100644 index ac6a43189d7ab..0000000000000 --- a/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php +++ /dev/null @@ -1,493 +0,0 @@ -objectManager = $objectManagerProvider->get(); - $this->directoryList = $directoryList; - $this->componentRegistrar = $componentRegistrar; - parent::__construct(); - } - - /** - * {@inheritdoc} - */ - protected function configure() - { - $options = [ - new InputOption( - self::INPUT_KEY_SERIALIZER, - null, - InputOption::VALUE_REQUIRED, - 'Serializer function that should be used (' . self::SERIALIZER_VALUE_SERIALIZE . '|' - . self::SERIALIZER_VALUE_IGBINARY . ') default: ' . self::SERIALIZER_VALUE_SERIALIZE - ), - new InputOption( - self::INPUT_KEY_EXTRA_CLASSES_FILE, - null, - InputOption::VALUE_REQUIRED, - 'Path to file with extra proxies and factories to generate' - ), - new InputOption( - self::INPUT_KEY_GENERATION, - null, - InputOption::VALUE_REQUIRED, - 'Absolute path to generated classes, /var/generation by default' - ), - new InputOption( - self::INPUT_KEY_DI, - null, - InputOption::VALUE_REQUIRED, - 'Absolute path to DI definitions directory, /var/di by default' - ), - new InputOption( - self::INPUT_KEY_EXCLUDE_PATTERN, - null, - InputOption::VALUE_REQUIRED, - 'Allows to exclude Paths from compilation (default is #[\\\\/]m1[\\\\/]#i)' - ), - ]; - $this->setName(self::NAME) - ->setDescription( - 'Generates all non-existing proxies and factories, and pre-compile class definitions, ' - . 'inheritance information and plugin definitions' - ) - ->setDefinition($options); - parent::configure(); - } - - /** - * Get module directories exclude patterns - * - * @return array - */ - private function getModuleExcludePatterns() - { - $modulesExcludePatterns = []; - foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $modulePath) { - $modulesExcludePatterns[] = "#^" . $modulePath . "/Test#"; - } - return $modulesExcludePatterns; - } - - /** - * Get library directories exclude patterns - * - * @return array - */ - private function getLibraryExcludePatterns() - { - $libraryExcludePatterns = []; - foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) as $libraryPath) { - $libraryExcludePatterns[] = "#^" . $libraryPath . "/([\\w]+/)?Test#"; - } - return $libraryExcludePatterns; - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $errors = $this->validate($input); - if ($errors) { - $output->writeln($errors); - return; - } - - $generationDir = $input->getOption(self::INPUT_KEY_GENERATION) ? $input->getOption(self::INPUT_KEY_GENERATION) - : $this->directoryList->getPath(DirectoryList::GENERATION); - $modulesExcludePatterns = $this->getModuleExcludePatterns(); - $testExcludePatterns = [ - "#^" . $this->directoryList->getPath(DirectoryList::SETUP) . "/[\\w]+/[\\w]+/Test#", - "#^" . $this->directoryList->getRoot() . "/dev/tools/Magento/Tools/[\\w]+/Test#" - ]; - $librariesExcludePatterns = $this->getLibraryExcludePatterns(); - $testExcludePatterns = array_merge($testExcludePatterns, $modulesExcludePatterns, $librariesExcludePatterns); - $fileExcludePatterns = $input->getOption('exclude-pattern') ? - [$input->getOption(self::INPUT_KEY_EXCLUDE_PATTERN)] : ['#[\\\\/]M1[\\\\/]#i']; - $fileExcludePatterns = array_merge($fileExcludePatterns, $testExcludePatterns); - /** @var Writer\Console logWriter Writer model for success messages */ - $logWriter = new Writer\Console($output); - $this->log = new Log($logWriter, $logWriter); - AutoloaderRegistry::getAutoloader()->addPsr4('Magento\\', $generationDir . '/Magento/'); - // 1 Code generation - $this->generateCode($generationDir, $fileExcludePatterns, $input); - // 2. Compilation - $this->compileCode($generationDir, $fileExcludePatterns, $input); - //Reporter - $this->log->report(); - if (!$this->log->hasError()) { - $output->writeln( - 'On *nix systems, verify the Magento application has permissions to modify files ' - . 'created by the compiler in the "var" directory. For instance, if you run the Magento application ' - . 'using Apache, the owner of the files in the "var" directory should be the Apache user (example ' - . 'command: "chown -R www-data:www-data /var" where MAGENTO_ROOT is the Magento ' - . 'root directory).' - ); - } - } - - /** - * Generate Code - * - * @param string $generationDir - * @param array $fileExcludePatterns - * @param InputInterface $input - * @return void - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - public function generateCode($generationDir, $fileExcludePatterns, $input) - { - // 1.1 Code scan - $filePatterns = ['php' => '/.*\.php$/', 'di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/']; - $directoryScanner = new Scanner\DirectoryScanner(); - foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $codeScanDir) { - $this->files = array_merge_recursive( - $this->files, - $directoryScanner->scan($codeScanDir, $filePatterns, $fileExcludePatterns) - ); - } - $this->files['di'][] = $this->directoryList->getPath( - \Magento\Framework\App\Filesystem\DirectoryList::CONFIG - ) . '/di.xml'; - $this->files['additional'] = [$input->getOption(self::INPUT_KEY_EXTRA_CLASSES_FILE)]; - $repositoryScanner = new Scanner\RepositoryScanner(); - $repositories = $repositoryScanner->collectEntities($this->files['di']); - $scanner = new Scanner\CompositeScanner(); - $scanner->addChild(new Scanner\PhpScanner($this->log), 'php'); - $scanner->addChild(new Scanner\XmlScanner($this->log), 'di'); - $scanner->addChild(new Scanner\ArrayScanner(), 'additional'); - $this->entities = $scanner->collectEntities($this->files); - $interceptorScanner = new Scanner\XmlInterceptorScanner(); - $this->entities['interceptors'] = $interceptorScanner->collectEntities($this->files['di']); - // 1.2 Generation of Factory and Additional Classes - $generatorIo = $this->objectManager->create( - \Magento\Framework\Code\Generator\Io::class, - ['generationDirectory' => $generationDir] - ); - $this->generator = $this->objectManager->create( - \Magento\Framework\Code\Generator::class, - ['ioObject' => $generatorIo] - ); - /** Initialize object manager for code generation based on configs */ - $this->generator->setObjectManager($this->objectManager); - $generatorAutoloader = new \Magento\Framework\Code\Generator\Autoloader($this->generator); - spl_autoload_register([$generatorAutoloader, 'load']); - - foreach ($repositories as $entityName) { - switch ($this->generator->generateClass($entityName)) { - case CodeGenerator::GENERATION_SUCCESS: - $this->log->add(Log::GENERATION_SUCCESS, $entityName); - break; - case CodeGenerator::GENERATION_ERROR: - $this->log->add(Log::GENERATION_ERROR, $entityName); - break; - case CodeGenerator::GENERATION_SKIP: - default: - //no log - break; - } - } - foreach (['php', 'additional'] as $type) { - sort($this->entities[$type]); - foreach ($this->entities[$type] as $entityName) { - switch ($this->generator->generateClass($entityName)) { - case CodeGenerator::GENERATION_SUCCESS: - $this->log->add(Log::GENERATION_SUCCESS, $entityName); - break; - case CodeGenerator::GENERATION_ERROR: - $this->log->add(Log::GENERATION_ERROR, $entityName); - break; - case CodeGenerator::GENERATION_SKIP: - default: - //no log - break; - } - } - } - } - - /** - * Compile Code - * - * @param string $generationDir - * @param array $fileExcludePatterns - * @param InputInterface $input - * @return void - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - private function compileCode($generationDir, $fileExcludePatterns, $input) - { - $diDir = $input->getOption(self::INPUT_KEY_DI) ? $input->getOption(self::INPUT_KEY_DI) : - $this->directoryList->getPath(DirectoryList::DI); - $relationsFile = $diDir . '/relations.ser'; - $pluginDefFile = $diDir . '/plugins.ser'; - $compilationDirs = [ - $this->directoryList->getPath(DirectoryList::SETUP) . '/Magento/Setup/Module', - $this->directoryList->getRoot() . '/dev/tools/Magento/Tools', - ]; - $compilationDirs = array_merge( - $compilationDirs, - $this->componentRegistrar->getPaths(ComponentRegistrar::MODULE), - $this->componentRegistrar->getPaths(ComponentRegistrar::LIBRARY) - ); - $serializer = $input->getOption(self::INPUT_KEY_SERIALIZER) == Igbinary::NAME ? new Igbinary() : new Standard(); - // 2.1 Code scan - $validator = new \Magento\Framework\Code\Validator(); - $validator->add(new \Magento\Framework\Code\Validator\ConstructorIntegrity()); - $validator->add(new \Magento\Framework\Code\Validator\ContextAggregation()); - $classesScanner = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner(); - $classesScanner->addExcludePatterns($fileExcludePatterns); - $directoryInstancesNamesList = new \Magento\Setup\Module\Di\Code\Reader\Decorator\Directory( - $this->log, - new \Magento\Framework\Code\Reader\ClassReader(), - $classesScanner, - $validator, - $generationDir - ); - foreach ($compilationDirs as $path) { - if (is_readable($path)) { - $directoryInstancesNamesList->getList($path); - } - } - $inheritanceScanner = new Scanner\InheritanceInterceptorScanner( - new \Magento\Framework\ObjectManager\InterceptableValidator() - ); - $this->entities['interceptors'] = $inheritanceScanner->collectEntities( - get_declared_classes(), - $this->entities['interceptors'] - ); - // 2.1.1 Generation of Proxy and Interceptor Classes - foreach (['interceptors', 'di'] as $type) { - foreach ($this->entities[$type] as $entityName) { - switch ($this->generator->generateClass($entityName)) { - case CodeGenerator::GENERATION_SUCCESS: - $this->log->add(Log::GENERATION_SUCCESS, $entityName); - break; - case CodeGenerator::GENERATION_ERROR: - $this->log->add(Log::GENERATION_ERROR, $entityName); - break; - case CodeGenerator::GENERATION_SKIP: - default: - //no log - break; - } - } - } - //2.1.2 Compile relations for Proxy/Interceptor classes - $directoryInstancesNamesList->getList($generationDir); - $relations = $directoryInstancesNamesList->getRelations(); - // 2.2 Compression - $relationsFileDir = dirname($relationsFile); - if (!file_exists($relationsFileDir)) { - mkdir($relationsFileDir, 0777, true); - } - $relations = array_filter($relations); - file_put_contents($relationsFile, $serializer->serialize($relations)); - // 3. Plugin Definition Compilation - $pluginScanner = new Scanner\CompositeScanner(); - $pluginScanner->addChild(new Scanner\PluginScanner(), 'di'); - $pluginDefinitions = []; - $pluginList = $pluginScanner->collectEntities($this->files); - $pluginDefinitionList = new \Magento\Framework\Interception\Definition\Runtime(); - foreach ($pluginList as $type => $entityList) { - foreach ($entityList as $entity) { - $pluginDefinitions[ltrim($entity, '\\')] = $pluginDefinitionList->getMethodList($entity); - } - } - $outputContent = $serializer->serialize($pluginDefinitions); - $pluginDefFileDir = dirname($pluginDefFile); - if (!file_exists($pluginDefFileDir)) { - mkdir($pluginDefFileDir, 0777, true); - } - file_put_contents($pluginDefFile, $outputContent); - } - - /** - * Check if all option values provided by the user are valid - * - * @param InputInterface $input - * @return string[] - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - private function validate(InputInterface $input) - { - $errors = []; - $options = $input->getOptions(); - foreach ($options as $key => $value) { - if (!$value) { - continue; - } - switch ($key) { - case self::INPUT_KEY_SERIALIZER: - if (($value !== self::SERIALIZER_VALUE_SERIALIZE) && ($value !== self::SERIALIZER_VALUE_IGBINARY)) { - $errors[] = 'Invalid value for command option \'' . self::INPUT_KEY_SERIALIZER - . '\'. Possible values (' . self::SERIALIZER_VALUE_SERIALIZE . '|' - . self::SERIALIZER_VALUE_IGBINARY . ').'; - } - break; - case self::INPUT_KEY_EXTRA_CLASSES_FILE: - if (!file_exists($value)) { - $errors[] = 'Path does not exist for the value of command option \'' - . self::INPUT_KEY_EXTRA_CLASSES_FILE . '\'.'; - } - break; - case self::INPUT_KEY_GENERATION: - $errorMsg = $this->validateOutputPath($value, self::INPUT_KEY_GENERATION); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } - break; - case self::INPUT_KEY_DI: - $errorMsg = $this->validateOutputPath($value, self::INPUT_KEY_DI); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } - break; - case self::INPUT_KEY_EXCLUDE_PATTERN: - if (@preg_match($value, null) === false) { - $errors[] = 'Invalid pattern for command option \'' . self::INPUT_KEY_EXCLUDE_PATTERN - . '\'.'; - } - break; - } - } - return $errors; - } - - /** - * Validate output path based on type - * - * @param string $value - * @param string $type - * @return string - */ - private function validateOutputPath($value, $type) - { - $errorMsg = ''; - if (!file_exists($value)) { - $errorMsg = 'Path does not exist for the value of command option \'' . $type . '\'.'; - } - if (file_exists($value) && !is_writeable($value)) { - $errorMsg .= 'Non-writable directory is provided by the value of command option \'' - . $type . '\'.'; - - } - return $errorMsg; - } -} diff --git a/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php b/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php index d91a1633ef038..fb34a028d4652 100644 --- a/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php +++ b/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php @@ -1,6 +1,6 @@ writeln('Generating profile with following params:'); foreach ($fixtureModel->getParamLabels() as $configKey => $label) { - $output->writeln(' |- ' . $label . ': ' . $fixtureModel->getValue($configKey) . ''); + $output->writeln( + ' |- ' . $label . ': ' . (is_array($fixtureModel->getValue($configKey)) === true + ? sizeof( + $fixtureModel->getValue($configKey)[array_keys($fixtureModel->getValue($configKey))[0]] + ) : $fixtureModel->getValue($configKey)) . '' + ); } /** @var $config \Magento\Indexer\Model\Config */ diff --git a/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php b/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php index 4731f9c4c5de4..c7cd5d6d9b235 100644 --- a/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php +++ b/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php @@ -1,6 +1,6 @@ installerFactory = $installerFactory; $this->deploymentConfig = $deploymentConfig; $this->objectManager = $objectManagerProvider->get(); + $this->localeValidator = $localeValidator; + $this->timezoneValidator = $timezoneValidator; + $this->currencyValidator = $currencyValidator; + $this->urlValidator = $urlValidator; parent::__construct(); } @@ -173,6 +205,7 @@ public function getOptionsList() public function validate(InputInterface $input) { $errors = []; + $errorMsg = ''; $options = $input->getOptions(); foreach ($options as $key => $value) { if (!$value) { @@ -180,99 +213,69 @@ public function validate(InputInterface $input) } switch ($key) { case StoreConfigurationDataMapper::KEY_BASE_URL: - /** @var Validator $url */ if (strcmp($value, '{{base_url}}') == 0) { break; } - $url = $this->objectManager->get(\Magento\Framework\Url\Validator::class); - if (!$url->isValid($value)) { - $errorMsgs = $url->getMessages(); - $errors[] = '' . 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL - . '\': ' . $errorMsgs[Validator::INVALID_URL] .''; - } + $errorMsg = $this->validateUrl( + $value, + StoreConfigurationDataMapper::KEY_BASE_URL, + ['http', 'https'] + ); + break; case StoreConfigurationDataMapper::KEY_LANGUAGE: - /** @var Locale $lists */ - $lists = $this->objectManager->get(\Magento\Framework\Validator\Locale::class); - $errorMsg = $this->validateCodes($lists, $value, StoreConfigurationDataMapper::KEY_LANGUAGE); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } + $errorMsg = $this->validateCodes( + $this->localeValidator, + $value, + StoreConfigurationDataMapper::KEY_LANGUAGE + ); break; case StoreConfigurationDataMapper::KEY_TIMEZONE: - /** @var Timezone $lists */ - $lists = $this->objectManager->get(\Magento\Framework\Validator\Timezone::class); - $errorMsg = $this->validateCodes($lists, $value, StoreConfigurationDataMapper::KEY_TIMEZONE); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } + $errorMsg = $this->validateCodes( + $this->timezoneValidator, + $value, + StoreConfigurationDataMapper::KEY_TIMEZONE + ); break; case StoreConfigurationDataMapper::KEY_CURRENCY: - /** @var Currency $lists */ - $lists = $this->objectManager->get(\Magento\Framework\Validator\Currency::class); - $errorMsg = $this->validateCodes($lists, $value, StoreConfigurationDataMapper::KEY_CURRENCY); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } + $errorMsg = $this->validateCodes( + $this->currencyValidator, + $value, + StoreConfigurationDataMapper::KEY_CURRENCY + ); break; case StoreConfigurationDataMapper::KEY_USE_SEF_URL: $errorMsg = $this->validateBinaryValue($value, StoreConfigurationDataMapper::KEY_USE_SEF_URL); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } break; case StoreConfigurationDataMapper::KEY_IS_SECURE: $errorMsg = $this->validateBinaryValue($value, StoreConfigurationDataMapper::KEY_IS_SECURE); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } break; case StoreConfigurationDataMapper::KEY_BASE_URL_SECURE: - try { - /** @var Validator $url */ - $url = $this->objectManager->get(\Magento\Framework\Url\Validator::class); - $errorMsgs = ''; - if (!$url->isValid($value)) { - $errorMsgs = $url->getMessages(); - if (!empty($errorMsgs)) { - $errors[] = '' . 'Command option \'' - . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE - . '\': ' . $errorMsgs[Validator::INVALID_URL] .''; - } - } - if (empty($errorMsgs) && strpos($value, 'https:') === false) { - throw new LocalizedException(new \Magento\Framework\Phrase("Invalid secure URL.")); - } - } catch (LocalizedException $e) { - $errors[] = '' . 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE - . '\': ' . $e->getLogMessage() .''; - } + $errorMsg = $this->validateUrl( + $value, + StoreConfigurationDataMapper::KEY_BASE_URL_SECURE, + ['https'] + ); break; case StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN: $errorMsg = $this->validateBinaryValue($value, StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } break; case StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY: $errorMsg = $this->validateBinaryValue( $value, StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY ); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } break; case StoreConfigurationDataMapper::KEY_JS_LOGGING: $errorMsg = $this->validateBinaryValue( $value, StoreConfigurationDataMapper::KEY_JS_LOGGING ); - if ($errorMsg !== '') { - $errors[] = $errorMsg; - } break; } + if ($errorMsg !== '') { + $errors[] = $errorMsg; + } } return $errors; } @@ -296,7 +299,7 @@ private function validateBinaryValue($value, $key) /** * Validate codes for languages, currencies or timezones * - * @param Locale|Timezone|Currency $lists + * @param LocaleValidator|TimezoneValidator|CurrencyValidator $lists * @param string $code * @param string $type * @return string @@ -310,4 +313,31 @@ private function validateCodes($lists, $code, $type) } return $errorMsg; } + + /** + * Validate URL + * + * @param string $url + * @param string $option + * @param array $allowedSchemes + * @return string + */ + private function validateUrl($url, $option, array $allowedSchemes) + { + $errorMsg = ''; + + if (!$this->urlValidator->isValid($url, $allowedSchemes)) { + $errorTemplate = 'Command option \'%s\': Invalid URL \'%s\'.' + . ' Domain Name should contain only letters, digits and hyphen.' + . ' And you should use only following schemes: \'%s\'.'; + $errorMsg = sprintf( + $errorTemplate, + $option, + $url, + implode(', ', $allowedSchemes) + ); + } + + return $errorMsg; + } } diff --git a/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php b/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php index 40823d5a2b162..d1aec5fa8eac2 100644 --- a/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php +++ b/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php @@ -1,6 +1,6 @@ installSchema(); $installer->installDataFixtures(); if (!$keepGenerated) { - $output->writeln('Please re-run Magento compile command'); + $output->writeln('Please re-run Magento compile command. Use the command "setup:di:compile"'); } return \Magento\Framework\Console\Cli::RETURN_SUCCESS; diff --git a/setup/src/Magento/Setup/Console/CommandList.php b/setup/src/Magento/Setup/Console/CommandList.php index 4bb5ac0181a79..d986160fa4f13 100644 --- a/setup/src/Magento/Setup/Console/CommandList.php +++ b/setup/src/Magento/Setup/Console/CommandList.php @@ -1,6 +1,6 @@ serviceManager = $serviceManager; - $this->input = $input; + $this->serviceManager = $serviceManager; + $this->input = $input; $this->filesystemDriver = $filesystemDriver; } /** - * Determine whether a CLI command is for compilation, and if so, clear the directory + * Determine whether a CLI command is for compilation, and if so, clear the directory. * - * @throws \Magento\Framework\Exception\FileSystemException + * @throws FileSystemException if generation directory is read-only * @return void */ public function handleCompilerEnvironment() @@ -60,8 +73,14 @@ public function handleCompilerEnvironment() ? $mageInitParams[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] : []; $directoryList = new DirectoryList(BP, $mageDirs); - $compileDirList[] = $directoryList->getPath(DirectoryList::GENERATION); - $compileDirList[] = $directoryList->getPath(DirectoryList::DI); + $compileDirList[] = $directoryList->getPath(DirectoryList::GENERATED_CODE); + $compileDirList[] = $directoryList->getPath(DirectoryList::GENERATED_METADATA); + + if (!$this->getGenerationDirectoryAccess()->check()) { + throw new FileSystemException( + new Phrase('Generation directory can not be written.') + ); + } foreach ($compileDirList as $compileDir) { if ($this->filesystemDriver->isExists($compileDir)) { @@ -69,4 +88,18 @@ public function handleCompilerEnvironment() } } } + + /** + * Retrieves generation directory access checker. + * + * @return GenerationDirectoryAccess the generation directory access checker + */ + private function getGenerationDirectoryAccess() + { + if (null === $this->generationDirectoryAccess) { + $this->generationDirectoryAccess = new GenerationDirectoryAccess($this->serviceManager); + } + + return $this->generationDirectoryAccess; + } } diff --git a/setup/src/Magento/Setup/Controller/AddDatabase.php b/setup/src/Magento/Setup/Controller/AddDatabase.php index 65fb1b684f35b..c3cab8a47b2c8 100644 --- a/setup/src/Magento/Setup/Controller/AddDatabase.php +++ b/setup/src/Magento/Setup/Controller/AddDatabase.php @@ -1,6 +1,6 @@ systemPackage->getInstalledSystemPackages([]); + $data['packages'] = $this->systemPackage->getInstalledSystemPackages(); $data['responseType'] = ResponseTypeInterface::RESPONSE_TYPE_SUCCESS; } catch (\Exception $e) { $data['error'] = $e->getMessage(); diff --git a/setup/src/Magento/Setup/Controller/Session.php b/setup/src/Magento/Setup/Controller/Session.php index 371365d11b62f..dde08e2cc0039 100644 --- a/setup/src/Magento/Setup/Controller/Session.php +++ b/setup/src/Magento/Setup/Controller/Session.php @@ -1,15 +1,11 @@ setTemplate('/error/404.phtml'); $this->getResponse()->setStatusCode(\Zend\Http\Response::STATUS_CODE_404); return $view; @@ -58,7 +54,7 @@ public function prolongAction() $objectManager = $this->objectManagerProvider->get(); /** @var \Magento\Framework\App\State $adminAppState */ $adminAppState = $objectManager->get(\Magento\Framework\App\State::class); - $adminAppState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMIN); + $adminAppState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML); $sessionConfig = $objectManager->get(\Magento\Backend\Model\Session\AdminConfig::class); /** @var \Magento\Backend\Model\Url $backendUrl */ $backendUrl = $objectManager->get(\Magento\Backend\Model\Url::class); @@ -74,19 +70,19 @@ public function prolongAction() ] ); $session->prolong(); - return new JsonModel(['success' => true]); + return new \Zend\View\Model\JsonModel(['success' => true]); } } catch (\Exception $e) { } - return new JsonModel(['success' => false]); + return new \Zend\View\Model\JsonModel(['success' => false]); } /** - * @return ViewModel|\Zend\Http\Response + * @return \Zend\View\Model\ViewModel|\Zend\Http\Response */ public function unloginAction() { - $view = new ViewModel(); + $view = new \Zend\View\Model\ViewModel(); $view->setTemplate('/error/401.phtml'); $this->getResponse()->setStatusCode(\Zend\Http\Response::STATUS_CODE_401); return $view; diff --git a/setup/src/Magento/Setup/Controller/StartUpdater.php b/setup/src/Magento/Setup/Controller/StartUpdater.php index f0e9c84ff4e5d..6939d04efcf42 100644 --- a/setup/src/Magento/Setup/Controller/StartUpdater.php +++ b/setup/src/Magento/Setup/Controller/StartUpdater.php @@ -1,6 +1,6 @@ urlValidator = $urlValidator; + } + + /** + * Validate URL + * + * @return JsonModel + */ + public function indexAction() + { + $params = Json::decode($this->getRequest()->getContent(), Json::TYPE_ARRAY); + $result = ['successUrl' => false, 'successSecureUrl' => true]; + + $hasBaseUrl = isset($params['address']['actual_base_url']); + $hasSecureBaseUrl = isset($params['https']['text']); + $hasSecureAdminUrl = !empty($params['https']['admin']); + $hasSecureFrontUrl = !empty($params['https']['front']); + $schemes = ['http', 'https']; + + // Validating of Base URL + if ($hasBaseUrl && $this->urlValidator->isValid($params['address']['actual_base_url'], $schemes)) { + $result['successUrl'] = true; + } + + // Validating of Secure Base URL + if ($hasSecureAdminUrl || $hasSecureFrontUrl) { + if (!($hasSecureBaseUrl && $this->urlValidator->isValid($params['https']['text'], $schemes))) { + $result['successSecureUrl'] = false; + } + } + + return new JsonModel($result); + } +} diff --git a/setup/src/Magento/Setup/Controller/ValidateAdminCredentials.php b/setup/src/Magento/Setup/Controller/ValidateAdminCredentials.php index 6833c1fba0c11..01461dd499586 100644 --- a/setup/src/Magento/Setup/Controller/ValidateAdminCredentials.php +++ b/setup/src/Magento/Setup/Controller/ValidateAdminCredentials.php @@ -1,6 +1,6 @@ populateUniqueAttributesQuantity(); + $attributeSets = $this->getAttributeSetsFixtureValue(); + if ($attributeSets === null) { + return; + } + $this->fixtureModel->resetObjectManager(); + /** @var \Magento\Catalog\Api\AttributeSetManagementInterface $attributeSetManagement */ + $attributeSetManagement = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\AttributeSetManagementInterface::class + ); + /** @var \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface $attributeGroupRepository */ + $attributeGroupRepository = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class + ); + + foreach ($attributeSets['attribute_set'] as $attributeSetData) { + //Create Attribute Set + /** @var \Magento\Eav\Api\Data\AttributeSetInterfaceFactory $attributeSetFactory */ + $attributeSetFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Eav\Api\Data\AttributeSetInterfaceFactory::class + ); + $attributeSet = $attributeSetFactory->create(); + $attributeSet->setAttributeSetName($attributeSetData['name']); + $attributeSet->setEntityTypeId(\Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE); + + $result = $attributeSetManagement->create($attributeSet, 4); + $attributeSetId = $result->getAttributeSetId(); + + //Create Attribute Group + /** @var \Magento\Eav\Api\Data\AttributeGroupInterfaceFactory $attributeGroupFactory */ + $attributeGroupFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Eav\Api\Data\AttributeGroupInterfaceFactory::class + ); + $attributeGroup = $attributeGroupFactory->create(); + $attributeGroup->setAttributeGroupName($result->getAttributeSetName() . ' - Group'); + $attributeGroup->setAttributeSetId($attributeSetId); + $attributeGroupRepository->save($attributeGroup); + $attributeGroupId = $attributeGroup->getAttributeGroupId(); + + /** @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository */ + $attributeRepository = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class + ); + /** @var \Magento\Catalog\Api\ProductAttributeManagementInterface $attributeManagementManagement */ + $attributeManagement = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\ProductAttributeManagementInterface::class + ); + + $attributesData = array_key_exists(0, $attributeSetData['attributes']['attribute']) + ? $attributeSetData['attributes']['attribute'] : [$attributeSetData['attributes']['attribute']]; + foreach ($attributesData as $attributeData) { + if ($this->uniqueAttributesQuantity === 0 + || (count($this->attributeIdsCache) < $this->uniqueAttributesQuantity)) { + //Create Attribute + /** @var \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory $attributeFactory */ + $attributeFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory::class + ); + + $optionsData = array_key_exists(0, $attributeData['options']['option']) + ? $attributeData['options']['option'] : [$attributeData['options']['option']]; + $options = []; + foreach ($optionsData as $optionData) { + /** @var \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory */ + $optionFactory = $this->fixtureModel->getObjectManager()->create( + \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory::class + ); + $option = $optionFactory->create(['data' => $optionData]); + $options[] = $option; + } + + $attribute = $attributeFactory->create(['data' => $attributeData]); + $attribute->setOptions($options); + + $result = $attributeRepository->save($attribute); + $attributeId = $result->getAttributeId(); + $this->fillAttributeIdsCache($attributeId); + } else { + $attributeId = $this->getAttributeIdFromCache(); + } + //Associate Attribute to Attribute Set + $sortOrder = 3; + + $attributeManagement->assign($attributeSetId, $attributeGroupId, $attributeId, $sortOrder); + } + } + } + + /** + * Get attribute ID from cache. + * + * @return int + */ + private function getAttributeIdFromCache() + { + $attributeId = next($this->attributeIdsCache); + if ($attributeId === false) { + $attributeId = reset($this->attributeIdsCache); + } + + return $attributeId; + } + + /** + * Fill attribute IDs cache. + * + * @param int $attributeId + * @return void + */ + private function fillAttributeIdsCache($attributeId) + { + if ($this->uniqueAttributesQuantity !== 0) { + $this->attributeIdsCache[] = $attributeId; + } + } + + /** + * Populate quantity of unique attributes to generate. + * + * @return void + */ + protected function populateUniqueAttributesQuantity() + { + $this->uniqueAttributesQuantity = $this->fixtureModel->getValue('unique_attributes_quantity', 0); + } + + /** + * {@inheritdoc} + */ + public function getActionTitle() + { + return 'Generating attribute sets'; + } + + /** + * {@inheritdoc} + */ + public function introduceParamLabels() + { + return [ + 'attribute_sets' => 'Attribute Sets' + ]; + } + + /** + * Get attribute sets fixture value. + * + * @return array|null + */ + protected function getAttributeSetsFixtureValue() + { + return $this->fixtureModel->getValue('attribute_sets', null); + } +} diff --git a/setup/src/Magento/Setup/Fixtures/BundleProductsFixture.php b/setup/src/Magento/Setup/Fixtures/BundleProductsFixture.php new file mode 100644 index 0000000000000..fc1af4e149ef7 --- /dev/null +++ b/setup/src/Magento/Setup/Fixtures/BundleProductsFixture.php @@ -0,0 +1,427 @@ + 'Bundle Product %s' . $suffix, + 'store_view_code' => '', + 'attribute_set_code' => 'Default', + 'product_type' => 'bundle', + 'categories' => $productCategory, + 'product_websites' => $productWebsite, + 'color' => '', + 'bundle_variation' => '', + 'cost' => '', + 'country_of_manufacture' => '', + 'created_at' => '2013-10-25 15:12:39', + 'custom_design' => '', + 'custom_design_from' => '', + 'custom_design_to' => '', + 'custom_layout_update' => '', + 'description' => '

    Bundle product description %s

    ', + 'enable_googlecheckout' => '1', + 'gallery' => '', + 'gift_message_available' => '', + 'gift_wrapping_available' => '', + 'gift_wrapping_price' => '', + 'has_options' => '1', + 'image' => '', + 'image_label' => '', + 'is_returnable' => 'Use config', + 'manufacturer' => '', + 'meta_description' => 'Bundle Product %s

    Bundle product description %s

    ', + 'meta_keyword' => 'Bundle Product %s', + 'meta_title' => 'Bundle Product %s', + 'minimal_price' => '', + 'msrp' => '', + 'msrp_display_actual_price_type' => 'Use config', + 'name' => 'Bundle Product %s' . $suffix, + 'news_from_date' => '', + 'news_to_date' => '', + 'options_container' => 'Block after Info Column', + 'page_layout' => '', + 'price' => '10', + 'quantity_and_stock_status' => 'In Stock', + 'related_tgtr_position_behavior' => '', + 'related_tgtr_position_limit' => '', + 'required_options' => '1', + 'short_description' => '', + 'small_image' => '', + 'small_image_label' => '', + 'special_from_date' => '', + 'special_price' => '', + 'special_to_date' => '', + 'product_online' => '1', + 'tax_class_name' => 'Taxable Goods', + 'thumbnail' => '', + 'thumbnail_label' => '', + 'updated_at' => '2013-10-25 15:12:39', + 'upsell_tgtr_position_behavior' => '', + 'upsell_tgtr_position_limit' => '', + 'url_key' => "bundle-product-%s{$suffix}", + 'url_path' => "bundle-product-%s{$suffix}", + 'visibility' => 'Catalog, Search', + 'weight' => '', + 'qty' => 333, + 'min_qty' => '0.0000', + 'use_config_min_qty' => '1', + 'is_qty_decimal' => '0', + 'backorders' => '0', + 'use_config_backorders' => '1', + 'min_sale_qty' => '1.0000', + 'use_config_min_sale_qty' => '1', + 'max_sale_qty' => '0.0000', + 'use_config_max_sale_qty' => '1', + 'is_in_stock' => '1', + 'notify_stock_qty' => '', + 'use_config_notify_stock_qty' => '1', + 'manage_stock' => '1', + 'use_config_manage_stock' => '1', + 'use_config_qty_increments' => '1', + 'qty_increments' => '0.0000', + 'use_config_enable_qty_inc' => '1', + 'enable_qty_increments' => '0', + 'is_decimal_divided' => '0', + 'bundle_price_type' => 'dynamic', + 'bundle_sku_type' => 'dynamic', + 'bundle_price_view' => 'Price range', + 'bundle_weight_type' => 'dynamic', + 'bundle_values' => $variation, + 'bundle_shipment_type' => 'separately', + ]; + } + + /** + * Get CSV template rows + * + * @param Closure|mixed $productCategory + * @param Closure|mixed $productWebsite + * + * @SuppressWarnings(PHPMD) + * + * @return array + */ + protected function getRows($productCategory, $productWebsite, $optionsNumber, $suffix = '') + { + $data = []; + $variation = []; + for ($i = 1; $i <= $optionsNumber; $i++) { + $productData = [ + 'sku' => "Bundle Product %s-option {$i}{$suffix}", + 'store_view_code' => '', + 'attribute_set_code' => 'Default', + 'product_type' => 'simple', + 'categories' => $productCategory, + 'product_websites' => $productWebsite, + 'cost' => '', + 'country_of_manufacture' => '', + 'created_at' => '2013-10-25 15:12:32', + 'custom_design' => '', + 'custom_design_from' => '', + 'custom_design_to' => '', + 'custom_layout_update' => '', + 'description' => '

    Bundle product option description %s

    ', + 'enable_googlecheckout' => '1', + 'gallery' => '', + 'gift_message_available' => '', + 'gift_wrapping_available' => '', + 'gift_wrapping_price' => '', + 'has_options' => '0', + 'image' => '', + 'image_label' => '', + 'is_returnable' => 'Use config', + 'manufacturer' => '', + 'meta_description' => 'Bundle Product Option %s

    Bundle product description 1

    ', + 'meta_keyword' => 'Bundle Product 1', + 'meta_title' => 'Bundle Product %s', + 'minimal_price' => '', + 'msrp' => '', + 'msrp_display_actual_price_type' => 'Use config', + 'name' => "Bundle Product {$suffix} - %s-option {$i}", + 'news_from_date' => '', + 'news_to_date' => '', + 'options_container' => 'Block after Info Column', + 'page_layout' => '', + 'price' => function () { return mt_rand(1, 1000) / 10; }, + 'quantity_and_stock_status' => 'In Stock', + 'related_tgtr_position_behavior' => '', + 'related_tgtr_position_limit' => '', + 'required_options' => '0', + 'short_description' => '', + 'small_image' => '', + 'small_image_label' => '', + 'special_from_date' => '', + 'special_price' => '', + 'special_to_date' => '', + 'product_online' => '1', + 'tax_class_name' => 'Taxable Goods', + 'thumbnail' => '', + 'thumbnail_label' => '', + 'updated_at' => '2013-10-25 15:12:32', + 'upsell_tgtr_position_behavior' => '', + 'upsell_tgtr_position_limit' => '', + 'url_key' => "simple-of-bundle-product-{$suffix}-%s-option-{$i}", + 'url_path' => "simple-of-bundle-product-{$suffix}-%s-option-{$i}", + 'visibility' => 'Not Visible Individually', + 'weight' => '1', + 'qty' => '111.0000', + 'min_qty' => '0.0000', + 'use_config_min_qty' => '1', + 'use_config_backorders' => '1', + 'use_config_min_sale_qty' => '1', + 'use_config_max_sale_qty' => '1', + 'is_in_stock' => '1', + 'use_config_notify_stock_qty' => '1', + 'use_config_manage_stock' => '1', + 'use_config_qty_increments' => '1', + 'use_config_enable_qty_inc' => '1', + 'enable_qty_increments' => '0', + 'is_decimal_divided' => '0', + ]; + $variation[] = implode( + ',', + [ + 'name=Bundle Option 1', + 'type=select', + 'required=1', + 'sku=' . $productData['sku'], + 'price=' . mt_rand(1, 1000) / 10, + 'default=0', + 'default_qty=1', + ] + ); + $data[] = $productData; + } + + $data[] = $this->generateBundleProduct($productCategory, $productWebsite, implode('|', $variation), $suffix); + return $data; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD) + */ + public function execute() + { + $bundlesCount = $this->fixtureModel->getValue('bundle_products', 0); + if (!$bundlesCount) { + return; + } + $this->fixtureModel->resetObjectManager(); + + /** @var \Magento\Store\Model\StoreManager $storeManager */ + $storeManager = $this->fixtureModel->getObjectManager()->create('Magento\Store\Model\StoreManager'); + /** @var $category \Magento\Catalog\Model\Category */ + $category = $this->fixtureModel->getObjectManager()->get('Magento\Catalog\Model\Category'); + + $result = []; + //Get all websites + $websites = $storeManager->getWebsites(); + foreach ($websites as $website) { + $websiteCode = $website->getCode(); + //Get all groups + $websiteGroups = $website->getGroups(); + foreach ($websiteGroups as $websiteGroup) { + $websiteGroupRootCategory = $websiteGroup->getRootCategoryId(); + $category->load($websiteGroupRootCategory); + $categoryResource = $category->getResource(); + $rootCategoryName = $category->getName(); + //Get all categories + $resultsCategories = $categoryResource->getAllChildren($category); + foreach ($resultsCategories as $resultsCategory) { + $category->load($resultsCategory); + $structure = explode('/', $category->getPath()); + $pathSize = count($structure); + if ($pathSize > 1) { + $path = []; + for ($i = 1; $i < $pathSize; $i++) { + $path[] = $category->load($structure[$i])->getName(); + } + array_shift($path); + $resultsCategoryName = implode('/', $path); + } else { + $resultsCategoryName = $category->getName(); + } + //Deleted root categories + if (trim($resultsCategoryName) != '') { + $result[$resultsCategory] = [$websiteCode, $resultsCategoryName, $rootCategoryName]; + } + } + } + } + $result = array_values($result); + + $productWebsite = function ($index) use ($result) { + return $result[$index % count($result)][0]; + }; + $productCategory = function ($index) use ($result) { + return $result[$index % count($result)][2] . '/' . $result[$index % count($result)][1]; + }; + + /** + * Create bundle products + */ + $pattern = new Pattern(); + $pattern->setHeaders($this->getHeaders()); + $pattern->setRowsSet( + $this->getRows( + $productCategory, + $productWebsite, + $this->fixtureModel->getValue('bundle_products_variation', 5000) + ) + ); + + /** @var \Magento\ImportExport\Model\Import $import */ + $import = $this->fixtureModel->getObjectManager()->create( + 'Magento\ImportExport\Model\Import', + [ + 'data' => [ + 'entity' => 'catalog_product', + 'behavior' => 'append', + 'validation_strategy' => 'validation-stop-on-errors', + ], + ] + ); + + $source = new Generator($pattern, $bundlesCount); + // it is not obvious, but the validateSource() will actually save import queue data to DB + if (!$import->validateSource($source)) { + throw new \Exception($import->getFormatedLogTrace()); + } + // this converts import queue into actual entities + if (!$import->importSource()) { + throw new \Exception($import->getFormatedLogTrace()); + } + } + // @codingStandardsIgnoreEnd + + /** + * {@inheritdoc} + */ + public function getActionTitle() + { + return 'Generating bundle products'; + } + + /** + * {@inheritdoc} + */ + public function introduceParamLabels() + { + return [ + 'bundle_products' => 'Bundle products', + ]; + } +} diff --git a/setup/src/Magento/Setup/Fixtures/CartPriceRulesFixture.php b/setup/src/Magento/Setup/Fixtures/CartPriceRulesFixture.php index 5e6a36d2f1d03..26fb84417f1c4 100755 --- a/setup/src/Magento/Setup/Fixtures/CartPriceRulesFixture.php +++ b/setup/src/Magento/Setup/Fixtures/CartPriceRulesFixture.php @@ -1,6 +1,6 @@ 'Configurable Product %s' . $suffix, + 'sku' => $this->getConfigurableProductSkuPattern() . $suffix, 'store_view_code' => '', - 'attribute_set_code' => 'Default', + 'attribute_set_code' => $attributeSetClosure, + 'additional_attributes' => $additionalAttributesClosure, 'product_type' => 'configurable', - 'categories' => $productCategory, - 'product_websites' => $productWebsite, + 'categories' => $productCategoryClosure, + 'product_websites' => $productWebsiteClosure, 'color' => '', 'configurable_variation' => '', 'cost' => '', @@ -162,7 +192,7 @@ private function generateConfigurableProduct($productCategory, $productWebsite, 'custom_design_from' => '', 'custom_design_to' => '', 'custom_layout_update' => '', - 'description' => '

    Configurable product description %s

    ', + 'description' => $descriptionClosure, 'enable_googlecheckout' => '1', 'gallery' => '', 'gift_message_available' => '', @@ -184,12 +214,12 @@ private function generateConfigurableProduct($productCategory, $productWebsite, 'news_to_date' => '', 'options_container' => 'Block after Info Column', 'page_layout' => '', - 'price' => '10', + 'price' => $priceClosure, 'quantity_and_stock_status' => 'In Stock', 'related_tgtr_position_behavior' => '', 'related_tgtr_position_limit' => '', 'required_options' => '1', - 'short_description' => '', + 'short_description' => $shortDescriptionClosure, 'small_image' => '', 'small_image_label' => '', 'special_from_date' => '', @@ -202,8 +232,8 @@ private function generateConfigurableProduct($productCategory, $productWebsite, 'updated_at' => '2013-10-25 15:12:39', 'upsell_tgtr_position_behavior' => '', 'upsell_tgtr_position_limit' => '', - 'url_key' => "configurable-product-%s{$suffix}", - 'url_path' => "configurable-product-%s{$suffix}", + 'url_key' => $this->getUrlKeyPrefix() . "{$suffix}", + 'url_path' => $this->getUrlKeyPrefix() . "{$suffix}", 'visibility' => 'Catalog, Search', 'weight' => '', 'qty' => 333, @@ -244,32 +274,51 @@ private function generateConfigurableProduct($productCategory, $productWebsite, '_media_label' => '', '_media_position' => '', '_media_is_disabled' => '', - 'configurable_variations' => $variation, + 'configurable_variations' => $variationClosure, ]; } /** * Get CSV template rows * - * @param Closure|mixed $productCategory - * @param Closure|mixed $productWebsite + * @param Closure|mixed $productCategoryClosure + * @param Closure|mixed $productWebsiteClosure + * @param Closure|mixed $shortDescriptionClosure + * @param Closure|mixed $descriptionClosure + * @param Closure|mixed $priceClosure + * @param Closure|mixed $attributeSetClosure + * @param Closure|mixed $additionalAttributesClosure + * @param Closure|mixed $variationClosure + * @param int $optionsNumber + * @param string $suffix * * @SuppressWarnings(PHPMD) * * @return array */ - protected function getRows($productCategory, $productWebsite, $optionsNumber, $suffix = '') + protected function getRows( + $productCategoryClosure, + $productWebsiteClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure, + $variationClosure, + $optionsNumber, + $suffix = '' + ) { $data = []; - $variation = []; for ($i = 1; $i <= $optionsNumber; $i++) { $productData = [ - 'sku' => "Configurable Product %s-option {$i}{$suffix}", + 'sku' => $this->getConfigurableOptionSkuPattern() . "{$i}{$suffix}", 'store_view_code' => '', - 'attribute_set_code' => 'Default', + 'attribute_set_code' => $attributeSetClosure, + 'additional_attributes' => $additionalAttributesClosure, 'product_type' => 'simple', - 'categories' => $productCategory, - 'product_websites' => $productWebsite, + 'categories' => $productCategoryClosure, + 'product_websites' => $productWebsiteClosure, 'color' => '', 'configurable_variation' => "option {$i}", 'cost' => '', @@ -279,7 +328,7 @@ protected function getRows($productCategory, $productWebsite, $optionsNumber, $s 'custom_design_from' => '', 'custom_design_to' => '', 'custom_layout_update' => '', - 'description' => '

    Configurable product description %s

    ', + 'description' => $descriptionClosure, 'enable_googlecheckout' => '1', 'gallery' => '', 'gift_message_available' => '', @@ -301,12 +350,12 @@ protected function getRows($productCategory, $productWebsite, $optionsNumber, $s 'news_to_date' => '', 'options_container' => 'Block after Info Column', 'page_layout' => '', - 'price' => function () { return mt_rand(1, 1000) / 10; }, + 'price' => $priceClosure, 'quantity_and_stock_status' => 'In Stock', 'related_tgtr_position_behavior' => '', 'related_tgtr_position_limit' => '', 'required_options' => '0', - 'short_description' => '', + 'short_description' => $shortDescriptionClosure, 'small_image' => '', 'small_image_label' => '', 'special_from_date' => '', @@ -319,8 +368,8 @@ protected function getRows($productCategory, $productWebsite, $optionsNumber, $s 'updated_at' => '2013-10-25 15:12:32', 'upsell_tgtr_position_behavior' => '', 'upsell_tgtr_position_limit' => '', - 'url_key' => "simple-of-configurable-product-{$suffix}-%s-option-{$i}", - 'url_path' => "simple-of-configurable-product-{$suffix}-%s-option-{$i}", + 'url_key' => $this->getOptionUrlKeyPrefix() . "-{$suffix}-%s-option-{$i}", + 'url_path' => $this->getOptionUrlKeyPrefix() . "-{$suffix}-%s-option-{$i}", 'variations' => '', 'variations_1382710717' => '', 'variations_1382710773' => '', @@ -366,21 +415,18 @@ protected function getRows($productCategory, $productWebsite, $optionsNumber, $s '_media_position' => '', '_media_is_disabled' => '', ]; - - $variation[] = implode( - ',', - [ - 'sku=' . $productData['sku'], - 'configurable_variation=' . $productData['configurable_variation'], - ] - ); $data[] = $productData; } $data[] = $this->generateConfigurableProduct( - $productCategory, - $productWebsite, - implode('|', $variation), + $productCategoryClosure, + $productWebsiteClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure, + $variationClosure, $suffix ); return $data; @@ -388,62 +434,160 @@ protected function getRows($productCategory, $productWebsite, $optionsNumber, $s /** * {@inheritdoc} + * @SuppressWarnings(PHPMD) */ public function execute() { - $configurableCount = $this->fixtureModel->getValue('configurable_products', 0); - if (!$configurableCount) { + $configurableProductsCount = $this->getConfigurableProductsValue(); + if (!$configurableProductsCount) { return; } - $this->fixtureModel->resetObjectManager(); + $simpleProductsCount = $this->fixtureModel->getValue('simple_products', 0); + $maxAmountOfWordsDescription = $this->getSearchConfigValue('max_amount_of_words_description'); + $maxAmountOfWordsShortDescription = $this->getSearchConfigValue('max_amount_of_words_short_description'); + $minAmountOfWordsDescription = $this->getSearchConfigValue('min_amount_of_words_description'); + $minAmountOfWordsShortDescription = $this->getSearchConfigValue('min_amount_of_words_short_description'); + $configurableProductsWithAttributes = []; - $result = $this->getCategoriesAndWebsites(); + if ($this->getAdditionalConfigurableProductsVariations() === null) { + $configurableProductsWithAttributes[$configurableProductsCount] + = $this->getConfigurableProductsVariationsValue(); + } else { + if (strpos($this->getAdditionalConfigurableProductsVariations(), ',')) { + $variations = explode(',', $this->getAdditionalConfigurableProductsVariations()); + } else { + $variations = [$this->getAdditionalConfigurableProductsVariations()]; + } - $result = array_values($result); + foreach ($variations as $variation) { + $value = explode(':', $variation); + $configurableProductsWithAttributes[$value[0]] = $value[1]; + } + } - $productWebsite = function ($index) use ($result) { - return $result[$index % count($result)][0]; - }; - $productCategory = function ($index) use ($result) { - return $result[$index % count($result)][2] . '/' . $result[$index % count($result)][1]; - }; + foreach ($configurableProductsWithAttributes as $productsCount => $variationsCount) { + $this->variationsCount = $variationsCount; + $configurableProductsCount = $productsCount; + $attributes = $this->getAttributes(); + $searchTerms = $this->getSearchTerms(); + $this->fixtureModel->resetObjectManager(); + $result = $this->getCategoriesAndWebsites(); + $result = array_values($result); + $dataGenerator = new DataGenerator(realpath(__DIR__ . '/' . 'dictionary.csv')); - /** - * Create configurable products - */ - $pattern = new Pattern(); - $pattern->setHeaders($this->getHeaders()); - $pattern->setRowsSet( - $this->getRows( - $productCategory, - $productWebsite, - $this->fixtureModel->getValue('configurable_products_variation', 3) - ) - ); + $productWebsiteClosure = function ($index) use ($result) { + return $result[$index % count($result)][0]; + }; + $productCategoryClosure = function ($index) use ($result) { + return $result[$index % count($result)][2] . '/' . $result[$index % count($result)][1]; + }; + $shortDescriptionClosure = function ($index) + use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsShortDescription, + $minAmountOfWordsShortDescription + ) { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + mt_srand($index); + return $dataGenerator->generate( + $minAmountOfWordsShortDescription, + $maxAmountOfWordsShortDescription, + 'shortDescription-' . $index + ) . ($index <= ($count * count($searchTerms)) ? ' ' + . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $descriptionClosure = function ($index) + use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsDescription, + $minAmountOfWordsDescription + ) { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + mt_srand($index); + return $dataGenerator->generate( + $minAmountOfWordsDescription, + $maxAmountOfWordsDescription, + 'description-' . $index + ) . ($index <= ($count * count($searchTerms)) + ? ' ' . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $priceClosure = function ($index) { + mt_srand($index); + switch (mt_rand(0, 3)) { + case 0: + return 9.99; + case 1: + return 5; + case 2: + return 1; + case 3: + return mt_rand(1, 10000) / 10; + } + }; + $attributeSetClosure = $this->getAttributeSetClosure($attributes, $result); + $variationClosure = $this->getVariationsClosure($attributes, $result, $variationsCount); + $additionalAttributesClosure = $this->getAdditionalAttributesClosure($attributes, $result); + /** + * Create configurable products + */ + $pattern = new Pattern(); + $pattern->setHeaders($this->getHeaders()); + $pattern->setRowsSet( + $this->getRows( + $productCategoryClosure, + $productWebsiteClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure, + $variationClosure, + $variationsCount + ) + ); - /** @var \Magento\ImportExport\Model\Import $import */ - $import = $this->fixtureModel->getObjectManager()->create( - \Magento\ImportExport\Model\Import::class, - [ - 'data' => [ - 'entity' => 'catalog_product', - 'behavior' => 'append', - 'validation_strategy' => 'validation-stop-on-errors', - ], - ] - ); + /** @var \Magento\ImportExport\Model\Import $import */ + $import = $this->fixtureModel->getObjectManager()->create( + \Magento\ImportExport\Model\Import::class, + [ + 'data' => [ + 'entity' => 'catalog_product', + 'behavior' => 'append', + 'validation_strategy' => 'validation-stop-on-errors', + ], + ] + ); - $source = $this->fixtureModel->getObjectManager()->create( - Generator::class, - ['rowPattern' => $pattern, 'count' => $configurableCount] - ); - // it is not obvious, but the validateSource() will actually save import queue data to DB - if (!$import->validateSource($source)) { - throw new \Exception($import->getFormatedLogTrace()); - } - // this converts import queue into actual entities - if (!$import->importSource()) { - throw new \Exception($import->getFormatedLogTrace()); + $source = $this->fixtureModel->getObjectManager()->create( + Generator::class, + ['rowPattern' => $pattern, 'count' => $configurableProductsCount] + ); + // it is not obvious, but the validateSource() will actually save import queue data to DB + if (!$import->validateSource($source)) { + throw new \Exception($import->getFormatedLogTrace()); + } + // this converts import queue into actual entities + if (!$import->importSource()) { + throw new \Exception($import->getFormatedLogTrace()); + } } } // @codingStandardsIgnoreEnd @@ -467,9 +611,10 @@ public function introduceParamLabels() } /** + * @override * @return array */ - private function getCategoriesAndWebsites() + protected function getCategoriesAndWebsites() { /** @var \Magento\Store\Model\StoreManager $storeManager */ $storeManager = $this->fixtureModel->getObjectManager()->get(\Magento\Store\Model\StoreManager::class); @@ -513,4 +658,166 @@ private function getCategoriesAndWebsites() } return $result; } + + /** + * Get configurable products value. + * + * @return int + */ + protected function getConfigurableProductsValue() + { + return $this->fixtureModel->getValue('configurable_products', 0); + } + + /** + * Get configurable products variations value. + * + * @return int + */ + protected function getConfigurableProductsVariationsValue() + { + return $this->fixtureModel->getValue('configurable_products_variation', 3); + } + + /** + * Get attribute set closure + * + * @param array $attributes + * @param array $result + * @return \Closure + */ + protected function getAttributeSetClosure(array $attributes, array $result) + { + return function ($index) use ($attributes, $result) { + mt_srand($index); + $attributeSet = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + return $attributeSet; + }; + } + + /** + * Get additional attributes closure. + * + * @param array $attributes + * @param array $result + * @return \Closure + */ + protected function getAdditionalAttributesClosure(array $attributes, array $result) + { + return function ($index, $variationIndex) use ($attributes, $result) { + $attributeValues = ''; + mt_srand($index); + $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + if ($attributeSetCode !== 'Default') { + foreach ($attributes[$attributeSetCode] as $attribute) { + $attributeValues = $attributeValues . $attribute['name'] . "=" . + $attribute['values'][$variationIndex % count($attribute['values'])] . ","; + } + } + return trim($attributeValues, ","); + }; + } + + /** + * Get variations closure. + * + * @param array $attributes + * @param array $result + * @param int $variationCount + * @return \Closure + */ + protected function getVariationsClosure(array $attributes, array $result, $variationCount) + { + return function ($index, $variationIndex) use ($attributes, $result, $variationCount) { + mt_srand($index); + $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + $skus = []; + for ($i = 1; $i <= $variationCount; $i++) { + $skus[] = 'sku=' . sprintf($this->getConfigurableOptionSkuPattern(), $index) . $i; + } + $values = []; + if ($attributeSetCode == 'Default') { + for ($i = 1; $i <= $variationCount; $i++) { + $values[] = 'configurable_variation=option ' . $i; + } + } else { + for ($i = $variationCount; $i > 0; $i--) { + $attributeValues = ''; + foreach ($attributes[$attributeSetCode] as $attribute) { + $attributeValues = $attributeValues . $attribute['name'] . "=" . + $attribute['values'][($variationIndex - $i) % count($attribute['values'])] . ","; + } + $values [] = $attributeValues; + } + } + $variations = []; + for ($i = 0; $i < $variationCount; $i++) { + $variations[] = trim(implode(",", [$skus[$i], $values[$i]]), ","); + } + return implode("|", $variations); + }; + } + + /** + * Get configurable product sku pattern. + * + * @return string + */ + private function getConfigurableProductSkuPattern() + { + return 'Configurable Product ' . $this->getConfigurableProductPrefix() . ' %s'; + } + + /** + * Get configurable option sku pattern. + * + * @return string + */ + protected function getConfigurableOptionSkuPattern() + { + return 'Configurable Product ' . $this->getConfigurableProductPrefix() . '%s-option'; + } + + /** + * Get url key prefix. + * + * @return string + */ + private function getUrlKeyPrefix() + { + return 'configurable-product' . $this->getConfigurableProductPrefix() . '-%s'; + } + + /** + * Get option url key prefix. + * + * @return string + */ + private function getOptionUrlKeyPrefix() + { + return 'simple-of-configurable-product' . $this->getConfigurableProductPrefix(); + } + + /** + * Get additional configurations for configurable products. + * + * @return string|null + */ + private function getAdditionalConfigurableProductsVariations() + { + return $this->fixtureModel->getValue('configurable_products_variations', null); + } + + /** + * Get configurable product prefix. + * + * @return string + */ + protected function getConfigurableProductPrefix() + { + return ''; + } } diff --git a/setup/src/Magento/Setup/Fixtures/CustomersFixture.php b/setup/src/Magento/Setup/Fixtures/CustomersFixture.php index ca29b4cf70447..112476516cce2 100644 --- a/setup/src/Magento/Setup/Fixtures/CustomersFixture.php +++ b/setup/src/Magento/Setup/Fixtures/CustomersFixture.php @@ -1,6 +1,6 @@ config = $this->fileParser->load($filename)->xmlToArray(); + $this->fileParser->getDom()->load($filename); + $this->fileParser->getDom()->xinclude(); + $this->config = $this->fileParser->xmlToArray(); } /** @@ -219,6 +221,12 @@ public function loadConfig($filename) */ public function getValue($key, $default = null) { - return isset($this->config['config']['profile'][$key]) ? $this->config['config']['profile'][$key] : $default; + return isset($this->config['config']['profile'][$key]) ? + ( + // Work around for how attributes are handled in the XML parser when injected via xinclude due to the + // files existing outside of the current working directory. + isset($this->config['config']['profile'][$key]['_value']) ? + $this->config['config']['profile'][$key]['_value'] : $this->config['config']['profile'][$key] + ) : $default; } } diff --git a/setup/src/Magento/Setup/Fixtures/IndexersStatesApplyFixture.php b/setup/src/Magento/Setup/Fixtures/IndexersStatesApplyFixture.php index 9a80889e9c232..f6cc76364f343 100644 --- a/setup/src/Magento/Setup/Fixtures/IndexersStatesApplyFixture.php +++ b/setup/src/Magento/Setup/Fixtures/IndexersStatesApplyFixture.php @@ -1,6 +1,6 @@ fixtureModel->getValue('configurable_products', 0); + $maxAmountOfWordsDescription = $this->getSearchConfigValue('max_amount_of_words_description'); + $maxAmountOfWordsShortDescription = $this->getSearchConfigValue('max_amount_of_words_short_description'); + $minAmountOfWordsDescription = $this->getSearchConfigValue('min_amount_of_words_description'); + $minAmountOfWordsShortDescription = $this->getSearchConfigValue('min_amount_of_words_short_description'); + $searchTerms = $this->getSearchTerms(); + $attributes = $this->getAttributes(); $this->fixtureModel->resetObjectManager(); - - /** @var \Magento\Store\Model\StoreManager $storeManager */ - $storeManager = $this->fixtureModel->getObjectManager()->create(\Magento\Store\Model\StoreManager::class); - /** @var $category \Magento\Catalog\Model\Category */ - $category = $this->fixtureModel->getObjectManager()->get(\Magento\Catalog\Model\Category::class); - - $result = []; - //Get all websites - $websites = $storeManager->getWebsites(); - foreach ($websites as $website) { - $websiteCode = $website->getCode(); - //Get all groups - $websiteGroups = $website->getGroups(); - foreach ($websiteGroups as $websiteGroup) { - $websiteGroupRootCategory = $websiteGroup->getRootCategoryId(); - $category->load($websiteGroupRootCategory); - $categoryResource = $category->getResource(); - //Get all categories - $resultsCategories = $categoryResource->getAllChildren($category); - foreach ($resultsCategories as $resultsCategory) { - $category->load($resultsCategory); - $structure = explode('/', $category->getPath()); - $pathSize = count($structure); - if ($pathSize > 1) { - $path = []; - for ($i = 0; $i < $pathSize; $i++) { - $path[] = $category->load($structure[$i])->getName(); - } - array_shift($path); - $resultsCategoryName = implode('/', $path); - } else { - $resultsCategoryName = $category->getName(); - } - //Deleted root categories - if (trim($resultsCategoryName) != '') { - $result[$resultsCategory] = [$websiteCode, $resultsCategoryName]; - } - } - } - } - $result = array_values($result); + $result = $this->getCategoriesAndWebsites(); + $dataGenerator = new DataGenerator(realpath(__DIR__ . '/' . 'dictionary.csv')); $productWebsite = function ($index) use ($result) { return $result[$index % count($result)][0]; @@ -76,10 +51,92 @@ public function execute() $productCategory = function ($index) use ($result) { return $result[$index % count($result)][1]; }; - - $generator = new Generator( - $this->getPattern($productWebsite, $productCategory), - $simpleProductsCount + $shortDescription = function ($index) use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsShortDescription, + $minAmountOfWordsShortDescription + ) { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $simpleProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + return $dataGenerator->generate( + $minAmountOfWordsShortDescription, + $maxAmountOfWordsShortDescription + ) . ($index <= ($count * count($searchTerms)) ? ' ' + . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $description = function ($index) use ( + $searchTerms, + $simpleProductsCount, + $configurableProductsCount, + $dataGenerator, + $maxAmountOfWordsDescription, + $minAmountOfWordsDescription + ) { + $count = $searchTerms === null + ? 0 + : round( + $searchTerms[$index % count($searchTerms)]['count'] * ( + $simpleProductsCount / ($simpleProductsCount + $configurableProductsCount) + ) + ); + return $dataGenerator->generate( + $minAmountOfWordsDescription, + $maxAmountOfWordsDescription + ) . ($index <= ($count * count($searchTerms)) ? ' ' + . $searchTerms[$index % count($searchTerms)]['term'] : ''); + }; + $price = function () { + switch (mt_rand(0, 3)) { + case 0: + return 9.99; + case 1: + return 5; + case 2: + return 1; + case 3: + return mt_rand(1, 10000)/10; + } + }; + $attributeSet = function ($index) use ($attributes, $result) { + mt_srand($index); + return (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + }; + $additionalAttributes = function ($index) use ($attributes, $result) { + $attributeValues = ''; + mt_srand($index); + $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result)) + ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default'); + if ($attributeSetCode !== 'Default') { + foreach ($attributes[$attributeSetCode] as $attribute) { + $attributeValues = $attributeValues . $attribute['name'] . "=" . + $attribute['values'][mt_rand(0, count($attribute['values']) - 1)] . ","; + } + } + return trim($attributeValues, ","); + }; + $generator = $this->fixtureModel->getObjectManager()->create( + Generator::class, + [ + 'rowPattern' => $this->getPattern( + $productWebsite, + $productCategory, + $shortDescription, + $description, + $price, + $attributeSet, + $additionalAttributes + ), + 'limit' => $simpleProductsCount + ] ); /** @var \Magento\ImportExport\Model\Import $import */ $import = $this->fixtureModel->getObjectManager()->create( @@ -93,9 +150,13 @@ public function execute() ] ); // it is not obvious, but the validateSource() will actually save import queue data to DB - $import->validateSource($generator); + if (!$import->validateSource($generator)) { + throw new \Exception($import->getFormatedLogTrace()); + } // this converts import queue into actual entities - $import->importSource(); + if (!$import->importSource()) { + throw new \Exception($import->getFormatedLogTrace()); + } } /** @@ -103,21 +164,34 @@ public function execute() * * @param Closure|int|string $productWebsiteClosure * @param Closure|int|string $productCategoryClosure + * @param Closure|int|string $shortDescriptionClosure + * @param Closure|int|string $descriptionClosure + * @param Closure|int|string $priceClosure + * @param Closure|int|string $attributeSetClosure + * @param Closure|int|string $additionalAttributesClosure * @return array */ - protected function getPattern($productWebsiteClosure, $productCategoryClosure) - { + protected function getPattern( + $productWebsiteClosure, + $productCategoryClosure, + $shortDescriptionClosure, + $descriptionClosure, + $priceClosure, + $attributeSetClosure, + $additionalAttributesClosure + ) { return [ - 'attribute_set_code' => 'Default', + 'attribute_set_code' => $attributeSetClosure, + 'additional_attributes' => $additionalAttributesClosure, 'product_type' => \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, 'product_websites' => $productWebsiteClosure, 'categories' => $productCategoryClosure, 'name' => 'Simple Product %s', - 'short_description' => 'Short simple product description %s', + 'short_description' => $shortDescriptionClosure, 'weight' => 1, - 'description' => 'Full simple product Description %s', + 'description' => $descriptionClosure, 'sku' => 'product_dynamic_%s', - 'price' => 10, + 'price' => $priceClosure, 'visibility' => 'Catalog, Search', 'product_online' => \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED, 'tax_class_name' => 'Taxable Goods', @@ -155,4 +229,122 @@ public function introduceParamLabels() 'simple_products' => 'Simple products' ]; } + + /** + * @return array + */ + protected function getAttributes() + { + $attributeSets = $this->getAttributeSets(); + $attributes = []; + + if ($attributeSets !== null && array_key_exists('attribute_set', $attributeSets)) { + foreach ($attributeSets['attribute_set'] as $attributeSet) { + $attributesData = array_key_exists(0, $attributeSet['attributes']['attribute']) + ? $attributeSet['attributes']['attribute'] : [$attributeSet['attributes']['attribute']]; + foreach ($attributesData as $attributeData) { + $values = []; + $optionsData = array_key_exists(0, $attributeData['options']['option']) + ? $attributeData['options']['option'] : [$attributeData['options']['option']]; + foreach ($optionsData as $optionData) { + $values[] = $optionData['label']; + } + $attributes[$attributeSet['name']][] = + ['name' => $attributeData['attribute_code'], 'values' => $values]; + } + } + } + return $attributes; + } + + /** + * @return array + */ + protected function getCategoriesAndWebsites() + { + /** @var \Magento\Store\Model\StoreManager $storeManager */ + $storeManager = $this->fixtureModel->getObjectManager()->create(\Magento\Store\Model\StoreManager::class); + /** @var $category \Magento\Catalog\Model\Category */ + $category = $this->fixtureModel->getObjectManager()->get(\Magento\Catalog\Model\Category::class); + + $result = []; + //Get all websites + $websites = $storeManager->getWebsites(); + foreach ($websites as $website) { + $websiteCode = $website->getCode(); + //Get all groups + $websiteGroups = $website->getGroups(); + foreach ($websiteGroups as $websiteGroup) { + $websiteGroupRootCategory = $websiteGroup->getRootCategoryId(); + $category->load($websiteGroupRootCategory); + $categoryResource = $category->getResource(); + //Get all categories + $resultsCategories = $categoryResource->getAllChildren($category); + foreach ($resultsCategories as $resultsCategory) { + $category->load($resultsCategory); + $structure = explode('/', $category->getPath()); + $pathSize = count($structure); + if ($pathSize > 1) { + $path = []; + for ($i = 0; $i < $pathSize; $i++) { + $path[] = $category->load($structure[$i])->getName(); + } + array_shift($path); + $resultsCategoryName = implode('/', $path); + } else { + $resultsCategoryName = $category->getName(); + } + //Deleted root categories + if (trim($resultsCategoryName) != '') { + $result[$resultsCategory] = [$websiteCode, $resultsCategoryName]; + } + } + } + } + return array_values($result); + } + + /** + * @return array + */ + protected function getSearchConfig() + { + if (!$this->searchConfig) { + $this->searchConfig = $this->fixtureModel->getValue('search_config', null); + } + return $this->searchConfig; + } + + /** + * @param string $name + * @return int|mixed + */ + protected function getSearchConfigValue($name) + { + return $this->getSearchConfig() === null + ? 0 : ($this->getSearchConfig()[$name] === null ? 0: $this->getSearchConfig()[$name]); + } + + /** + * @return array + */ + protected function getSearchTerms() + { + $searchTerms = $this->fixtureModel->getValue('search_terms', null); + if ($searchTerms !== null) { + $searchTerms = array_key_exists(0, $searchTerms['search_term']) + ? $searchTerms['search_term'] : [$searchTerms['search_term']]; + } + return $searchTerms; + } + + /** + * Get attribute sets. + * + * @return array|null + */ + private function getAttributeSets() + { + return $this->fixtureModel->getValue('attribute_sets', null); + } } diff --git a/setup/src/Magento/Setup/Fixtures/StoresFixture.php b/setup/src/Magento/Setup/Fixtures/StoresFixture.php index dcd7dd5b6f50c..c4d692fa19be6 100644 --- a/setup/src/Magento/Setup/Fixtures/StoresFixture.php +++ b/setup/src/Magento/Setup/Fixtures/StoresFixture.php @@ -1,6 +1,6 @@ getHeaders() as $key) { if (isset($row[$key])) { if (is_callable($row[$key])) { - $row[$key] = call_user_func($row[$key], $index); + $row[$key] = call_user_func($row[$key], $index, $generatorKey); } else { $row[$key] = str_replace('%s', $index, $row[$key]); } diff --git a/setup/src/Magento/Setup/Model/ConfigGenerator.php b/setup/src/Magento/Setup/Model/ConfigGenerator.php index 140f5a739889c..b070da8ada199 100644 --- a/setup/src/Magento/Setup/Model/ConfigGenerator.php +++ b/setup/src/Magento/Setup/Model/ConfigGenerator.php @@ -1,6 +1,6 @@ set( - ObjectManagerFactory::CONFIG_PATH_DEFINITION_FORMAT, - $data[ConfigOptionsListConstants::INPUT_KEY_DEFINITION_FORMAT] - ); - } - - return $configData; + return null; } /** diff --git a/setup/src/Magento/Setup/Model/ConfigModel.php b/setup/src/Magento/Setup/Model/ConfigModel.php index cc956ad443ebd..f1fd56abede81 100644 --- a/setup/src/Magento/Setup/Model/ConfigModel.php +++ b/setup/src/Magento/Setup/Model/ConfigModel.php @@ -1,6 +1,6 @@ dictionaryFile = $dictionaryFile; + $this->readData(); + $this->generatedValues = []; + } + + /** + * Read data from file. + * + * @return void + */ + protected function readData() + { + $f = fopen($this->dictionaryFile, 'r'); + while (!feof($f) && is_array($line = fgetcsv($f))) { + $this->dictionaryData[] = $line[0]; + } + } + + /** + * Generate string of random word data. + * + * @param int $minAmountOfWords + * @param int $maxAmountOfWords + * @param string|null $key + * @return string + */ + public function generate($minAmountOfWords, $maxAmountOfWords, $key = null) + { + $numberOfWords = mt_rand($minAmountOfWords, $maxAmountOfWords); + $result = ''; + + if ($key === null || !array_key_exists($key, $this->generatedValues)) { + for ($i = 0; $i < $numberOfWords; $i++) { + $result .= ' ' . $this->dictionaryData[mt_rand(0, count($this->dictionaryData) - 1)]; + } + $result = trim($result); + + if ($key !== null) { + $this->generatedValues[$key] = $result; + } + } else { + $result = $this->generatedValues[$key]; + } + return $result; + } +} diff --git a/setup/src/Magento/Setup/Model/DateTime/DateTimeProvider.php b/setup/src/Magento/Setup/Model/DateTime/DateTimeProvider.php index 1ac281a8d37c4..daf39705592f4 100644 --- a/setup/src/Magento/Setup/Model/DateTime/DateTimeProvider.php +++ b/setup/src/Magento/Setup/Model/DateTime/DateTimeProvider.php @@ -1,6 +1,6 @@ objectManagerProvider->get()->get(\Magento\Framework\App\State::class); - $appState->setAreaCode('setup'); + $appState->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL); $configData = $userConfig->getConfigData($data); if (count($configData) === 0) { return; @@ -1262,7 +1262,7 @@ private function generateListOfModuleContext($resource, $type) } /** - * Clear var/generation and reset object manager + * Clear generated/code and reset object manager * * @return void */ diff --git a/setup/src/Magento/Setup/Model/Installer/Progress.php b/setup/src/Magento/Setup/Model/Installer/Progress.php index 26dd06e7d37a4..aff5a12394b8c 100644 --- a/setup/src/Magento/Setup/Model/Installer/Progress.php +++ b/setup/src/Magento/Setup/Model/Installer/Progress.php @@ -1,6 +1,6 @@ self::COMPOSER_SHOW, - self::PARAM_PACKAGE => $package, - self::PARAM_AVAILABLE => true - ]; - - $applicationFactory = $this->objectManagerProvider->get() - ->get(\Magento\Framework\Composer\MagentoComposerApplicationFactory::class); - /** @var \Magento\Composer\MagentoComposerApplication $application */ - $application = $applicationFactory->create(); - - $result = $application->runComposerCommand($commandParams); - $matches = []; - preg_match($versionsPattern, $result, $matches); - if (isset($matches[1])) { - return explode(', ', $matches[1]); - } + } + + return $this->getAvailableVersionsFromAllRepositories($package); + } + + /** + * Get available versions of package by "composer show" command + * + * @param string $package + * @return array + * @exception \RuntimeException + */ + private function getAvailableVersionsFromAllRepositories($package) + { + $versionsPattern = '/^versions\s*\:\s(.+)$/m'; + + $commandParams = [ + self::PARAM_COMMAND => self::COMPOSER_SHOW, + self::PARAM_PACKAGE => $package, + self::PARAM_AVAILABLE => true + ]; + + $applicationFactory = $this->objectManagerProvider->get() + ->get(\Magento\Framework\Composer\MagentoComposerApplicationFactory::class); + /** @var \Magento\Composer\MagentoComposerApplication $application */ + $application = $applicationFactory->create(); + + $result = $application->runComposerCommand($commandParams); + $matches = []; + preg_match($versionsPattern, $result, $matches); + if (isset($matches[1])) { + return explode(', ', $matches[1]); } throw new \RuntimeException( diff --git a/setup/src/Magento/Setup/Model/PayloadValidator.php b/setup/src/Magento/Setup/Model/PayloadValidator.php index b024b028cb81f..6cab630ca7716 100644 --- a/setup/src/Magento/Setup/Model/PayloadValidator.php +++ b/setup/src/Magento/Setup/Model/PayloadValidator.php @@ -1,6 +1,6 @@ checkXDebugNestedLevel(), - $this->checkPopulateRawPostSetting() + $this->checkPopulateRawPostSetting(), + $this->checkFunctionsExistence() ); foreach ($settings as $setting) { @@ -316,6 +317,33 @@ private function checkPopulateRawPostSetting() return $data; } + /** + * Check whether all special functions exists + * + * @return array + */ + private function checkFunctionsExistence() + { + $data = []; + $requiredFunctions = [ + [ + 'name' => 'imagecreatefromjpeg', + 'message' => 'You must have installed GD library with --with-jpeg-dir=DIR option.', + 'helpUrl' => 'http://php.net/manual/en/image.installation.php', + ], + ]; + + foreach ($requiredFunctions as $function) { + $data['missed_function_' . $function['name']] = [ + 'message' => $function['message'], + 'helpUrl' => $function['helpUrl'], + 'error' => !function_exists($function['name']), + ]; + } + + return $data; + } + /** * Normalize PHP Version * diff --git a/setup/src/Magento/Setup/Model/RequestDataConverter.php b/setup/src/Magento/Setup/Model/RequestDataConverter.php index bd924c16f3da0..439b177bf1320 100644 --- a/setup/src/Magento/Setup/Model/RequestDataConverter.php +++ b/setup/src/Magento/Setup/Model/RequestDataConverter.php @@ -1,6 +1,6 @@ getInstalledSystemPackages($systemPackages); + $systemPackages = $this->getInstalledSystemPackages(); foreach ($systemPackages as $systemPackage) { - $versions = []; $systemPackageInfo = $this->infoCommand->run($systemPackage); if (!$systemPackageInfo) { throw new \RuntimeException("We cannot retrieve information on $systemPackage."); } - $versions = $this->getSystemPackageVersions($systemPackageInfo, $versions); + $versions = $this->getSystemPackageVersions($systemPackageInfo); - if ($systemPackageInfo['name'] == 'magento/product-community-edition') { + if ($systemPackageInfo['name'] == static::EDITION_COMMUNITY) { $currentCE = $systemPackageInfo[InfoCommand::CURRENT_VERSION]; } + + if ($systemPackageInfo['name'] == static::EDITION_ENTERPRISE) { + $currentEE = $systemPackageInfo[InfoCommand::CURRENT_VERSION]; + } + if (count($versions) > 1) { $versions[0]['name'] .= ' (latest)'; } @@ -80,36 +93,45 @@ public function getPackageVersions() ]; } - if (!in_array('magento/product-enterprise-edition', $systemPackages)) { + if (!in_array(static::EDITION_ENTERPRISE, $systemPackages)) { $result = array_merge($this->getAllowedEnterpriseVersions($currentCE), $result); } + if ( + in_array(static::EDITION_ENTERPRISE, $systemPackages) + && !in_array(static::EDITION_B2B, $systemPackages) + ) { + $result = array_merge($this->getAllowedB2BVersions($currentEE), $result); + } + $result = $this->formatPackages($result); return $result; } /** + * Retrieve allowed EE versions + * * @param string $currentCE * @return array */ public function getAllowedEnterpriseVersions($currentCE) { $result = []; - $enterpriseVersions = $this->infoCommand->run('magento/product-enterprise-edition'); + $enterpriseVersions = $this->infoCommand->run(static::EDITION_ENTERPRISE); $eeVersions = []; $maxVersion = ''; - if (is_array($enterpriseVersions) && array_key_exists('available_versions', $enterpriseVersions)) { + if (is_array($enterpriseVersions) && array_key_exists(InfoCommand::AVAILABLE_VERSIONS, $enterpriseVersions)) { $enterpriseVersions = $this->sortVersions($enterpriseVersions); - if (isset($enterpriseVersions['available_versions'][0])) { - $maxVersion = $enterpriseVersions['available_versions'][0]; + if (isset($enterpriseVersions[InfoCommand::AVAILABLE_VERSIONS][0])) { + $maxVersion = $enterpriseVersions[InfoCommand::AVAILABLE_VERSIONS][0]; } $eeVersions = $this->filterEeVersions($currentCE, $enterpriseVersions, $maxVersion); } if (!empty($eeVersions)) { $result[] = [ - 'package' => 'magento/product-enterprise-edition', + 'package' => static::EDITION_ENTERPRISE, 'versions' => $eeVersions, ]; } @@ -117,18 +139,81 @@ public function getAllowedEnterpriseVersions($currentCE) } /** + * Retrieve allowed B2B versions + * + * @param string $currentEE + * @return array + */ + public function getAllowedB2BVersions($currentEE) + { + $result = []; + $versions = $this->fetchInfoVersions(static::EDITION_B2B); + $versionsPrepared = []; + $maxVersion = ''; + + if ($versions[InfoCommand::AVAILABLE_VERSIONS]) { + $versions = $this->sortVersions($versions); + if (isset($versions[InfoCommand::AVAILABLE_VERSIONS][0])) { + $maxVersion = $versions[InfoCommand::AVAILABLE_VERSIONS][0]; + } + $versionsPrepared = $this->filterB2bVersions($currentEE, $versions, $maxVersion); + } + + if ($versionsPrepared) { + $result[] = [ + 'package' => static::EDITION_B2B, + 'versions' => $versionsPrepared, + ]; + } + + return $result; + } + + /** + * Fetching of info command response to display all correct versions + * + * @param string $command + * @return array + */ + private function fetchInfoVersions($command) + { + $versions = (array)$this->infoCommand->run($command); + + $versions[InfoCommand::CURRENT_VERSION] = isset($versions[InfoCommand::CURRENT_VERSION]) + ? $versions[InfoCommand::CURRENT_VERSION] + : null; + $versions[InfoCommand::AVAILABLE_VERSIONS] = isset($versions[InfoCommand::AVAILABLE_VERSIONS]) + ? $versions[InfoCommand::AVAILABLE_VERSIONS] + : null; + $versions[InfoCommand::AVAILABLE_VERSIONS] = array_unique( + array_merge( + (array)$versions[InfoCommand::CURRENT_VERSION], + (array)$versions[InfoCommand::AVAILABLE_VERSIONS] + ) + ); + + return $versions; + } + + /** + * Retrieve package versions + * * @param array $systemPackageInfo - * @param array $versions * @return array */ - public function getSystemPackageVersions($systemPackageInfo, $versions) + public function getSystemPackageVersions($systemPackageInfo) { $editionType = ''; - if ($systemPackageInfo['name'] == 'magento/product-community-edition') { + $versions = []; + + if ($systemPackageInfo['name'] == static::EDITION_COMMUNITY) { $editionType .= 'CE'; - } elseif ($systemPackageInfo['name'] == 'magento/product-enterprise-edition') { + } elseif ($systemPackageInfo['name'] == static::EDITION_ENTERPRISE) { $editionType .= 'EE'; + } elseif ($systemPackageInfo['name'] == static::EDITION_B2B) { + $editionType .= 'B2B'; } + foreach ($systemPackageInfo[InfoCommand::NEW_VERSIONS] as $version) { $versions[] = ['id' => $version, 'name' => 'Version ' . $version . ' ' . $editionType, 'current' => false]; } @@ -144,20 +229,18 @@ public function getSystemPackageVersions($systemPackageInfo, $versions) } /** - * @param array $systemPackages * @return array * @throws \RuntimeException */ - public function getInstalledSystemPackages($systemPackages) + public function getInstalledSystemPackages() { - $systemPackages = []; $locker = $this->magentoComposerApplication->createComposer()->getLocker(); /** @var \Composer\Package\CompletePackage $package */ foreach ($locker->getLockedRepository()->getPackages() as $package) { $packageName = $package->getName(); if ($this->composerInfo->isSystemPackage($packageName)) { - if ($packageName == 'magento/product-community-edition') { + if ($packageName == static::EDITION_COMMUNITY) { if ($this->composerInfo->isPackageInComposerJson($packageName)) { $systemPackages[] = $packageName; } @@ -183,7 +266,7 @@ public function getInstalledSystemPackages($systemPackages) */ public function sortVersions($enterpriseVersions) { - usort($enterpriseVersions['available_versions'], function ($versionOne, $versionTwo) { + usort($enterpriseVersions[InfoCommand::AVAILABLE_VERSIONS], function ($versionOne, $versionTwo) { if (version_compare($versionOne, $versionTwo, '==')) { return 0; } @@ -220,7 +303,7 @@ private function formatPackages($packages) usort($versions, function ($versionOne, $versionTwo) { if (version_compare($versionOne['id'], $versionTwo['id'], '==')) { - if ($versionOne['package'] === 'magento/product-community-edition') { + if ($versionOne['package'] === static::EDITION_COMMUNITY) { return 1; } return 0; @@ -240,11 +323,11 @@ private function formatPackages($packages) public function filterEeVersions($currentCE, $enterpriseVersions, $maxVersion) { $eeVersions = []; - foreach ($enterpriseVersions['available_versions'] as $version) { - $requires = $this->composerInfo->getPackageRequirements('magento/product-enterprise-edition', $version); - if (array_key_exists('magento/product-community-edition', $requires)) { + foreach ($enterpriseVersions[InfoCommand::AVAILABLE_VERSIONS] as $version) { + $requires = $this->composerInfo->getPackageRequirements(static::EDITION_ENTERPRISE, $version); + if (array_key_exists(static::EDITION_COMMUNITY, $requires)) { /** @var \Composer\Package\Link $ceRequire */ - $ceRequire = $requires['magento/product-community-edition']; + $ceRequire = $requires[static::EDITION_COMMUNITY]; if (version_compare( $ceRequire->getConstraint()->getPrettyString(), $currentCE, @@ -260,4 +343,36 @@ public function filterEeVersions($currentCE, $enterpriseVersions, $maxVersion) } return $eeVersions; } + + /** + * Filtering B2B versions + * + * @param string $currentEE + * @param array $b2bVersions + * @param string $maxVersion + * @return array + */ + public function filterB2bVersions($currentEE, $b2bVersions, $maxVersion) + { + $b2bVersionsPrepared = []; + foreach ($b2bVersions[InfoCommand::AVAILABLE_VERSIONS] as $version) { + $requires = $this->composerInfo->getPackageRequirements(static::EDITION_B2B, $version); + if (array_key_exists(static::EDITION_ENTERPRISE, $requires)) { + /** @var \Composer\Package\Link $eeRequire */ + $eeRequire = $requires[static::EDITION_ENTERPRISE]; + if (version_compare( + $eeRequire->getConstraint()->getPrettyString(), + $currentEE, + '>=' + )) { + $name = 'Version ' . $version . ' B2B'; + if ($maxVersion == $version) { + $name .= ' (latest)'; + } + $b2bVersionsPrepared[] = ['id' => $version, 'name' => $name, 'current' => false]; + } + } + } + return $b2bVersionsPrepared; + } } diff --git a/setup/src/Magento/Setup/Model/ThemeDependencyCheckerFactory.php b/setup/src/Magento/Setup/Model/ThemeDependencyCheckerFactory.php index 305574c6b72e7..d6f2ff8b29f3c 100644 --- a/setup/src/Magento/Setup/Model/ThemeDependencyCheckerFactory.php +++ b/setup/src/Magento/Setup/Model/ThemeDependencyCheckerFactory.php @@ -1,6 +1,6 @@ classesScanner->getList($path) as $className) { try { - if (!strpos($path, 'generation')) { // validate all classes except classes in var/generation dir + // validate all classes except classes in generated/code dir + $generatedCodeDir = DirectoryList::getDefaultConfig()[DirectoryList::GENERATED_CODE]; + if (!strpos($path, $generatedCodeDir[DirectoryList::PATH])) { $this->validator->validate($className); } $nameList[] = $className; diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileScanner.php index da4839f494f6a..5a2cb8703f1a5 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/FileScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/FileScanner.php @@ -1,6 +1,6 @@ isScanned = true; } -} \ No newline at end of file +} diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/Type.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/Type.php index e05fffd0623f0..fecd61e4747b3 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/Type.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/Type.php @@ -1,7 +1,7 @@ initialize(); - $serialized = serialize($config); - file_put_contents($this->directoryList->getPath(DirectoryList::DI) . '/' . $key . '.ser', $serialized); + file_put_contents( + $this->directoryList->getPath(DirectoryList::GENERATED_METADATA) . '/' . $key . '.ser', + $this->getSerializer()->serialize($config) + ); } /** @@ -50,8 +58,23 @@ public function write($key, array $config) */ private function initialize() { - if (!file_exists($this->directoryList->getPath(DirectoryList::DI))) { - mkdir($this->directoryList->getPath(DirectoryList::DI)); + if (!file_exists($this->directoryList->getPath(DirectoryList::GENERATED_METADATA))) { + mkdir($this->directoryList->getPath(DirectoryList::GENERATED_METADATA)); + } + } + + /** + * Get serializer + * + * @return SerializerInterface + * @deprecated + */ + private function getSerializer() + { + if (null === $this->serializer) { + $this->serializer = \Magento\Framework\App\ObjectManager::getInstance() + ->get(Serialize::class); } + return $this->serializer; } } diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php index 79e7272099704..8a1f28f62e0ff 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php @@ -1,7 +1,7 @@ _fileHandler); + if (is_resource($this->_fileHandler)) { + fclose($this->_fileHandler); + } + } + + /** + * Destructor for closing file handler + */ + public function __destruct() + { + if (is_resource($this->_fileHandler)) { + fclose($this->_fileHandler); + } } } diff --git a/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv/Stdo.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv/Stdo.php index 2b75bf83b4a34..6f8be9c4c2789 100644 --- a/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv/Stdo.php +++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv/Stdo.php @@ -1,6 +1,6 @@ getMessage() . ' Row #' . ($key + 1) . '.'); } + + if (null === $path) { + continue; + } + $filename = $path . $this->_locale . '.' . $this->_getFileExtension(); $files[$filename][$phrase->getPhrase()] = $phrase; } diff --git a/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/Csv.php b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/Csv.php index d037410ed773c..5effd7069480f 100644 --- a/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/Csv.php +++ b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/Csv.php @@ -1,6 +1,6 @@ getConnection($connectionName)->getIndexName($tableName, $fields, $indexType); + return $this->getConnection($connectionName)->getIndexName($this->getTable($tableName), $fields, $indexType); } /** @@ -46,7 +46,7 @@ public function getFkName( $connectionName = ResourceConnection::DEFAULT_CONNECTION ) { return $this->getConnection($connectionName)->getForeignKeyName( - $priTableName, + $this->getTable($priTableName), $priColumnName, $refTableName, $refColumnName diff --git a/setup/src/Magento/Setup/Module/Setup/ResourceConfig.php b/setup/src/Magento/Setup/Module/Setup/ResourceConfig.php index 620ab3e6c8aa1..a8741e97a7a3f 100644 --- a/setup/src/Magento/Setup/Module/Setup/ResourceConfig.php +++ b/setup/src/Magento/Setup/Module/Setup/ResourceConfig.php @@ -1,6 +1,6 @@ getApplication(); $serviceManager = $application->getServiceManager(); + if ($serviceManager->get(\Magento\Framework\App\DeploymentConfig::class)->isAvailable()) { /** @var \Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider */ $objectManagerProvider = $serviceManager->get(\Magento\Setup\Model\ObjectManagerProvider::class); @@ -122,7 +123,7 @@ public function authPreDispatch($event) $objectManager = $objectManagerProvider->get(); /** @var \Magento\Framework\App\State $adminAppState */ $adminAppState = $objectManager->get(\Magento\Framework\App\State::class); - $adminAppState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMIN); + $adminAppState->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML); /** @var \Magento\Backend\Model\Session\AdminConfig $sessionConfig */ $sessionConfig = $objectManager->get(\Magento\Backend\Model\Session\AdminConfig::class); $cookiePath = $this->getSetupCookiePath($objectManager); @@ -135,17 +136,26 @@ public function authPreDispatch($event) 'appState' => $adminAppState ] ); - if (!$objectManager->get(\Magento\Backend\Model\Auth::class)->isLoggedIn()) { + /** @var \Magento\Backend\Model\Auth $auth */ + $authentication = $objectManager->get(\Magento\Backend\Model\Auth::class); + + if ( + !$authentication->isLoggedIn() || + !$adminSession->isAllowed('Magento_Backend::setup_wizard') + ) { $adminSession->destroy(); + /** @var \Zend\Http\Response $response */ $response = $event->getResponse(); $baseUrl = Http::getDistroBaseUrlPath($_SERVER); $response->getHeaders()->addHeaderLine('Location', $baseUrl . 'index.php/session/unlogin'); $response->setStatusCode(302); $event->stopPropagation(); + return $response; } } } + return false; } diff --git a/setup/src/Magento/Setup/Mvc/View/Http/InjectTemplateListener.php b/setup/src/Magento/Setup/Mvc/View/Http/InjectTemplateListener.php index 027c3f8d36233..cebca17dfd571 100644 --- a/setup/src/Magento/Setup/Mvc/View/Http/InjectTemplateListener.php +++ b/setup/src/Magento/Setup/Mvc/View/Http/InjectTemplateListener.php @@ -1,6 +1,6 @@ deployer = $this->getMock(\Magento\Deploy\Model\Deployer::class, [], [], '', false); + $this->deployer = $this->getMock(\Magento\Deploy\Model\DeployManager::class, [], [], '', false); $this->filesUtil = $this->getMock(\Magento\Framework\App\Utility\Files::class, [], [], '', false); $this->appState = $this->getMock(\Magento\Framework\App\State::class, [], [], '', false); diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php index 22df0b92a3984..3839d99abdd97 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php @@ -1,6 +1,6 @@ fixtureModel->expects($this->once())->method('loadConfig')->with('path_to_profile.xml'); $this->fixtureModel->expects($this->once())->method('initObjectManager'); $this->fixtureModel->expects($this->once())->method('loadFixtures'); - + $commandTester = new CommandTester($this->command); $commandTester->execute(['profile' => 'path_to_profile.xml']); } /** * @expectedException \RuntimeException - * @expectedExceptionMessage Not enough arguments. + * @expectedExceptionMessage Not enough arguments */ public function testExecuteInvalidLanguageArgument() { diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoAdminUriCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoAdminUriCommandTest.php index f63c8cc8fcf59..0d0c3b9c3efd5 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoAdminUriCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InfoAdminUriCommandTest.php @@ -1,6 +1,6 @@ urlValidatorMock = $this->getMock(UrlValidator::class, [], [], '', false); + $this->localeValidatorMock = $this->getMock(LocaleValidator::class, [], [], '', false); + $this->timezoneValidatorMock = $this->getMock(TimezoneValidator::class, [], [], '', false); + $this->currencyValidatorMock = $this->getMock(CurrencyValidator::class, [], [], '', false); + $this->installerFactory = $this->getMock(\Magento\Setup\Model\InstallerFactory::class, [], [], '', false); $this->deploymentConfig = $this->getMock(\Magento\Framework\App\DeploymentConfig::class, [], [], '', false); $this->installer = $this->getMock(\Magento\Setup\Model\Installer::class, [], [], '', false); @@ -62,7 +93,11 @@ protected function setUp() $this->command = new InstallStoreConfigurationCommand( $this->installerFactory, $this->deploymentConfig, - $objectManagerProvider + $objectManagerProvider, + $this->localeValidatorMock, + $this->timezoneValidatorMock, + $this->currencyValidatorMock, + $this->urlValidatorMock ); } @@ -102,41 +137,11 @@ public function testExecuteNotInstalled() */ public function testExecuteInvalidData(array $option, $error) { - $url= $this->getMock(\Magento\Framework\Url\Validator::class, [], [], '', false); - $url->expects($this->any())->method('isValid')->will($this->returnValue(false)); - if (!isset($option['--' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE])) { - $url->expects($this->any())->method('getMessages')->will($this->returnValue([ - Validator::INVALID_URL => 'Invalid URL.' - ])); - } - $localeLists= $this->getMock(\Magento\Framework\Validator\Locale::class, [], [], '', false); - $localeLists->expects($this->any())->method('isValid')->will($this->returnValue(false)); - $timezoneLists= $this->getMock(\Magento\Framework\Validator\Timezone::class, [], [], '', false); - $timezoneLists->expects($this->any())->method('isValid')->will($this->returnValue(false)); - $currencyLists= $this->getMock(\Magento\Framework\Validator\Currency::class, [], [], '', false); - $currencyLists->expects($this->any())->method('isValid')->will($this->returnValue(false)); - - $returnValueMapOM = [ - [ - \Magento\Framework\Url\Validator::class, - $url - ], - [ - \Magento\Framework\Validator\Locale::class, - $localeLists - ], - [ - \Magento\Framework\Validator\Timezone::class, - $timezoneLists - ], - [ - \Magento\Framework\Validator\Currency::class, - $currencyLists - ], - ]; - $this->objectManager->expects($this->any()) - ->method('get') - ->will($this->returnValueMap($returnValueMapOM)); + $this->localeValidatorMock->expects($this->any())->method('isValid')->willReturn(false); + $this->timezoneValidatorMock->expects($this->any())->method('isValid')->willReturn(false); + $this->currencyValidatorMock->expects($this->any())->method('isValid')->willReturn(false); + $this->urlValidatorMock->expects($this->any())->method('isValid')->willReturn(false); + $this->deploymentConfig->expects($this->once()) ->method('isAvailable') ->will($this->returnValue(true)); @@ -144,7 +149,7 @@ public function testExecuteInvalidData(array $option, $error) ->method('create'); $commandTester = new CommandTester($this->command); $commandTester->execute($option); - $this->assertEquals($error . PHP_EOL, $commandTester->getDisplay()); + $this->assertContains($error, $commandTester->getDisplay()); } /** @@ -155,48 +160,54 @@ public function validateDataProvider() return [ [ ['--' . StoreConfigurationDataMapper::KEY_BASE_URL => 'sampleUrl'], - 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL . '\': Invalid URL.' + 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL . '\': Invalid URL \'sampleUrl\'.' + ], + [ + ['--' . StoreConfigurationDataMapper::KEY_BASE_URL => 'http://example.com_test'], + 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL + . '\': Invalid URL \'http://example.com_test\'.' ], [ ['--' . StoreConfigurationDataMapper::KEY_LANGUAGE => 'sampleLanguage'], 'Command option \'' . StoreConfigurationDataMapper::KEY_LANGUAGE - . '\': Invalid value. To see possible values, run command \'bin/magento info:language:list\'.' + . '\': Invalid value. To see possible values, run command \'bin/magento info:language:list\'.' ], [ ['--' . StoreConfigurationDataMapper::KEY_TIMEZONE => 'sampleTimezone'], 'Command option \'' . StoreConfigurationDataMapper::KEY_TIMEZONE - . '\': Invalid value. To see possible values, run command \'bin/magento info:timezone:list\'.' + . '\': Invalid value. To see possible values, run command \'bin/magento info:timezone:list\'.' ], [ ['--' . StoreConfigurationDataMapper::KEY_CURRENCY => 'sampleLanguage'], 'Command option \'' . StoreConfigurationDataMapper::KEY_CURRENCY - . '\': Invalid value. To see possible values, run command \'bin/magento info:currency:list\'.' + . '\': Invalid value. To see possible values, run command \'bin/magento info:currency:list\'.' ], [ ['--' . StoreConfigurationDataMapper::KEY_USE_SEF_URL => 'invalidValue'], 'Command option \'' . StoreConfigurationDataMapper::KEY_USE_SEF_URL - . '\': Invalid value. Possible values (0|1).' + . '\': Invalid value. Possible values (0|1).' ], [ ['--' . StoreConfigurationDataMapper::KEY_IS_SECURE => 'invalidValue'], 'Command option \'' . StoreConfigurationDataMapper::KEY_IS_SECURE - . '\': Invalid value. Possible values (0|1).' + . '\': Invalid value. Possible values (0|1).' ], [ ['--' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE => 'http://www.sample.com'], 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE - . '\': Invalid secure URL.' + . '\': Invalid URL \'http://www.sample.com\'.' ], [ ['--' . StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN => 'invalidValue'], 'Command option \'' . StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN - . '\': Invalid value. Possible values (0|1).' + . '\': Invalid value. Possible values (0|1).' ], [ ['--' . StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY => 'invalidValue'], 'Command option \'' . StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY - . '\': Invalid value. Possible values (0|1).' + . '\': Invalid value. Possible values (0|1).' ], + ]; } } diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php index 126cbadb6a53b..7e6cd17b2639b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Setup\Model\InstallerFactory::class, [], [], '', false); $installer = $this->getMock(\Magento\Setup\Model\Installer::class, [], [], '', false); @@ -20,6 +25,25 @@ public function testExecute() $installer->expects($this->at(2))->method('installDataFixtures'); $installerFactory->expects($this->once())->method('create')->willReturn($installer); $commandTester = new CommandTester(new UpgradeCommand($installerFactory)); - $this->assertSame(Cli::RETURN_SUCCESS, $commandTester->execute([])); + $this->assertSame(Cli::RETURN_SUCCESS, $commandTester->execute($options)); + $this->assertEquals($expectedString, $commandTester->getDisplay()); + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + [ + 'options' => [], + 'expectedString' => 'Please re-run Magento compile command. Use the command "setup:di:compile"' + . PHP_EOL + ], + [ + 'options' => ['--keep-generated' => true], + 'expectedString' => '' + ], + ]; } } diff --git a/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php b/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php index ce13e6977e773..2cb2ecf840f5f 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php @@ -1,6 +1,6 @@ serviceManagerMock = $this->getMockBuilder(\Zend\ServiceManager\ServiceManager::class) + $this->serviceManagerMock = $this->getMockBuilder(ServiceManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->inputMock = $this->getMockBuilder(ArgvInput::class) ->disableOriginalConstructor() ->getMock(); - $this->inputMock = $this->getMockBuilder(\Symfony\Component\Console\Input\ArgvInput::class) + $this->filesystemDriverMock = $this->getMockBuilder(File::class) ->disableOriginalConstructor() ->getMock(); - $this->filesystemDriverMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Driver\File::class) + $this->generationDirectoryAccessMock = $this->getMockBuilder(GenerationDirectoryAccess::class) ->disableOriginalConstructor() ->getMock(); + $this->model = (new ObjectManager($this))->getObject( - \Magento\Setup\Console\CompilerPreparation::class, + CompilerPreparation::class, [ 'serviceManager' => $this->serviceManagerMock, 'input' => $this->inputMock, - 'filesystemDriver' => $this->filesystemDriverMock + 'filesystemDriver' => $this->filesystemDriverMock, + 'generationDirectoryAccess' => $this->generationDirectoryAccessMock, ] ); } @@ -56,21 +77,31 @@ public function setUp() */ public function testClearGenerationDirWhenNeeded($commandName, $isCompileCommand, $isHelpOption, $dirExists = false) { - $this->inputMock->expects($this->once())->method('getFirstArgument')->willReturn($commandName); + $this->inputMock->expects($this->once()) + ->method('getFirstArgument') + ->willReturn($commandName); $this->inputMock->expects($this->atLeastOnce()) ->method('hasParameterOption') - ->with( - $this->logicalOr('--help', '-h') - )->willReturn($isHelpOption); + ->with($this->logicalOr('--help', '-h')) + ->willReturn($isHelpOption); + if ($isCompileCommand && !$isHelpOption) { $this->filesystemDriverMock->expects($this->exactly(2)) ->method('isExists') ->willReturn($dirExists); - $this->filesystemDriverMock->expects($this->exactly(((int)$dirExists) * 2))->method('deleteDirectory'); + $this->filesystemDriverMock->expects($this->exactly(((int)$dirExists) * 2)) + ->method('deleteDirectory'); } else { - $this->filesystemDriverMock->expects($this->never())->method('isExists'); - $this->filesystemDriverMock->expects($this->never())->method('deleteDirectory'); + $this->filesystemDriverMock->expects($this->never()) + ->method('isExists'); + $this->filesystemDriverMock->expects($this->never()) + ->method('deleteDirectory'); } + + $this->generationDirectoryAccessMock->expects($this->any()) + ->method('check') + ->willReturn(true); + $this->model->handleCompilerEnvironment(); } @@ -108,10 +139,6 @@ public function testGenerationDirectoryFromInitParams() $customGenerationDirectory = '/custom/generated/code/directory'; $defaultDiDirectory = '/custom/di/directory'; $mageInitParams = ['MAGE_DIRS' => ['generation' => ['path' => $customGenerationDirectory]]]; - - $this->inputMock->expects($this->once()) - ->method('getFirstArgument') - ->willReturn(DiCompileCommand::NAME); $dirValueMap = [ [ $customGenerationDirectory, @@ -122,16 +149,24 @@ public function testGenerationDirectoryFromInitParams() true ] ]; - // Filesystem mock - $this->filesystemDriverMock->expects($this->exactly(2))->method('isExists')->willReturn(true); + + $this->inputMock->expects($this->once()) + ->method('getFirstArgument') + ->willReturn(DiCompileCommand::NAME); + $this->filesystemDriverMock->expects($this->exactly(2)) + ->method('isExists') + ->willReturn(true); $this->filesystemDriverMock->expects($this->exactly(2)) ->method('deleteDirectory') - ->will($this->returnValueMap($dirValueMap)); - + ->willReturnMap($dirValueMap); $this->serviceManagerMock->expects($this->once()) ->method('get') ->with(InitParamListener::BOOTSTRAP_PARAM) ->willReturn($mageInitParams); + $this->generationDirectoryAccessMock->expects($this->once()) + ->method('check') + ->willReturn(true); + $this->model->handleCompilerEnvironment(); } @@ -139,10 +174,6 @@ public function testGenerationDirectoryFromCliOption() { $customGenerationDirectory = '/custom/generated/code/directory'; $customDiDirectory = '/custom/di/directory'; - - $this->inputMock->expects($this->once()) - ->method('getFirstArgument') - ->willReturn(DiCompileCommand::NAME); $dirResultMap = [ [ $this->logicalNot($this->equalTo($customGenerationDirectory)), @@ -154,10 +185,18 @@ public function testGenerationDirectoryFromCliOption() ] ]; - $this->filesystemDriverMock->expects($this->exactly(2))->method('isExists')->willReturn(true); + $this->inputMock->expects($this->once()) + ->method('getFirstArgument') + ->willReturn(DiCompileCommand::NAME); + $this->filesystemDriverMock->expects($this->exactly(2)) + ->method('isExists') + ->willReturn(true); $this->filesystemDriverMock->expects($this->exactly(2)) ->method('deleteDirectory') - ->will($this->returnValueMap($dirResultMap)); + ->willReturnMap($dirResultMap); + $this->generationDirectoryAccessMock->expects($this->once()) + ->method('check') + ->willReturn(true); $this->model->handleCompilerEnvironment(); } diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/AddDatabaseTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/AddDatabaseTest.php index 64c431d946ea2..4673cff9dd291 100644 --- a/setup/src/Magento/Setup/Test/Unit/Controller/AddDatabaseTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Controller/AddDatabaseTest.php @@ -1,6 +1,6 @@ getMockBuilder(UrlValidator::class) + ->disableOriginalConstructor() + ->getMock(); + $validator->expects($this->any()) + ->method('isValid') + ->willReturnMap($returnMap); + + /** @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject $requestMock */ + $requestMock = $this->getMockBuilder(RequestInterface::class) + ->getMockForAbstractClass(); + $requestMock->expects($this->once()) + ->method('getContent') + ->willReturn(json_encode($requestJson)); + + $controller = $objectManagerHelper->getObject( + UrlCheck::class, + ['urlValidator' => $validator] + ); + $objectManagerHelper->setBackwardCompatibleProperty($controller, 'request', $requestMock); + + $this->assertEquals(new JsonModel($expectedResult), $controller->indexAction()); + } + + /** + * @return array + */ + public function indexActionDataProvider() + { + return [ + [ + 'requestJson' => [ + 'address' => [ + 'actual_base_url' => 'http://localhost' + ] + ], + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + [ + 'requestJson' => [ + 'address' => [ + 'actual_base_url' => 'http://localhost.com_test' + ] + ], + 'expectedResult' => ['successUrl' => false, 'successSecureUrl' => true] + ], + [ + 'requestJson' => [ + 'address' => [ + 'actual_base_url' => 'http://localhost.com_test' + ], + 'https' => [ + 'admin' => false, + 'front' => false, + 'text' => '' + ] + ], + 'expectedResult' => ['successUrl' => false, 'successSecureUrl' => true] + ], + [ + 'requestJson' => [ + 'address' => [ + 'actual_base_url' => 'http://localhost.com:8080' + ], + 'https' => [ + 'admin' => true, + 'front' => false, + 'text' => 'https://example.com.ua/' + ] + ], + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + [ + 'requestJson' => [ + 'address' => [ + 'actual_base_url' => 'http://localhost.com:8080/folder_name/' + ], + 'https' => [ + 'admin' => false, + 'front' => true, + 'text' => 'https://example.com.ua/' + ] + ], + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + [ + 'requestJson' => [ + 'address' => [ + 'actual_base_url' => 'http://localhost.com:8080/folder_name/' + ], + 'https' => [ + 'admin' => true, + 'front' => true, + 'text' => 'https://example.com.ua:8090/folder_name/' + ] + ], + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + ]; + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/WebConfigurationTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/WebConfigurationTest.php index 829c64651e346..b6b5fc6ae6608 100644 --- a/setup/src/Magento/Setup/Test/Unit/Controller/WebConfigurationTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Controller/WebConfigurationTest.php @@ -1,6 +1,6 @@ fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new AttributeSetsFixture($this->fixtureModelMock); + } + + public function testExecute() + { + $attributeSets = [ + 'attribute_set' => [ + [ + 'name' => 'attribute set name', + 'attributes' => [ + 'attribute' => [ + [ + 'is_required' => 1, + 'is_visible_on_front' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'default_value' => 'yellow1', + 'attribute_code' => 'mycolor', + 'is_searchable' => '1', + 'frontend_label' => 'mycolor', + 'frontend_input' => 'select', + 'options' => [ + 'option' => [ + [ + 'label' => 'yellow1', + 'value' => '' + ] + ] + ] + ] + ] + ] + ] + ] + ]; + $attributeSet = $attributeSets['attribute_set'][0]; + + // Mock Attribute Sets + $attributeSetMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeSetInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeSetMock->expects($this->once()) + ->method('setAttributeSetName') + ->with("attribute set name"); + $attributeSetMock->expects($this->once()) + ->method('setEntityTypeId') + ->with(\Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE); + $attributeSetMock->expects($this->any()) + ->method('getAttributeSetName') + ->willReturn($attributeSet['name']); + + $attributeSetFactoryMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeSetInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $attributeSetFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($attributeSetMock); + + $attributeSetManagementMock = $this->getMockBuilder(\Magento\Catalog\Api\AttributeSetManagementInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeSetManagementMock->expects($this->once()) + ->method('create') + ->with($attributeSetMock, '4') + ->willReturn($attributeSetMock); + + //Mock Attribute Groups + $attributeGroupMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeGroupInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeGroupMock->expects($this->once()) + ->method('setAttributeGroupName') + ->with($attributeSetMock->getAttributeSetName() . ' - Group'); + $attributeGroupMock->expects($this->once()) + ->method('setAttributeSetId') + ->with($attributeSetMock->getAttributeSetId()); + + $attributeGroupFactoryMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeGroupInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $attributeGroupFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($attributeGroupMock); + + $productAttributeGroupRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeGroupRepoMock->expects($this->once()) + ->method('save') + ->with($attributeGroupMock) + ->willReturn($attributeGroupMock); + + // Mock Attributes + $attributeMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductAttributeInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $attributeFactoryMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $attributeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($attributeMock); + + //Mock Attribute Options + $optionMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeOptionInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $optionFactoryMock = $this->getMockBuilder(\Magento\Eav\Api\Data\AttributeOptionInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $optionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($optionMock); + + $productAttributeRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeRepoMock->expects($this->once()) + ->method('save') + ->with($attributeMock) + ->willReturn($attributeMock); + + $productAttributeManagementMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeManagementInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeManagementMock->expects($this->once()) + ->method('assign') + ->willReturn($attributeMock->getAttributeId()); + + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerMock->expects($this->at(0)) + ->method('create') + ->willReturn($attributeSetManagementMock); + $objectManagerMock->expects($this->at(1)) + ->method('create') + ->willReturn($productAttributeGroupRepoMock); + $objectManagerMock->expects($this->at(2)) + ->method('create') + ->willReturn($attributeSetFactoryMock); + $objectManagerMock->expects($this->at(3)) + ->method('create') + ->willReturn($attributeGroupFactoryMock); + $objectManagerMock->expects($this->at(4)) + ->method('create') + ->willReturn($productAttributeRepoMock); + $objectManagerMock->expects($this->at(5)) + ->method('create') + ->willReturn($productAttributeManagementMock); + $objectManagerMock->expects($this->at(6)) + ->method('create') + ->willReturn($attributeFactoryMock); + $objectManagerMock->expects($this->at(7)) + ->method('create') + ->willReturn($optionFactoryMock); + + $this->fixtureModelMock + ->expects($this->any()) + ->method('getValue') + ->willReturn($attributeSets); + + $this->fixtureModelMock + ->expects($this->any()) + ->method('getObjectManager') + ->will($this->returnValue($objectManagerMock)); + + $this->model->execute(); + } + + public function testNoFixtureConfigValue() + { + $attributeSetManagementMock = $this->getMockBuilder(\Magento\Catalog\Api\AttributeSetManagementInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeSetManagementMock->expects($this->never())->method('create'); + + $productAttributeGroupRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeGroupRepoMock->expects($this->never())->method('save'); + + $productAttributeRepoMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeRepoMock->expects($this->never())->method('save'); + + $productAttributeManagementMock = $this->getMockBuilder( + \Magento\Catalog\Api\ProductAttributeManagementInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $productAttributeManagementMock->expects($this->never())->method('assign'); + + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\AttributeSetManagementInterface::class)) + ->willReturn($attributeSetManagementMock); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\ProductAttributeGroupRepositoryInterface::class)) + ->willReturn($productAttributeGroupRepoMock); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\ProductAttributeRepositoryInterface::class)) + ->willReturn($productAttributeRepoMock); + $objectManagerMock->expects($this->never()) + ->method('create') + ->with($this->equalTo(\Magento\Catalog\Api\ProductAttributeManagementInterface::class)) + ->willReturn($productAttributeManagementMock); + + $this->fixtureModelMock + ->expects($this->never()) + ->method('getObjectManager') + ->will($this->returnValue($objectManagerMock)); + $this->fixtureModelMock + ->expects($this->any()) + ->method('getValue') + ->willReturn(null); + + $this->model->execute(); + } + + public function testGetActionTitle() + { + $this->assertSame('Generating attribute sets', $this->model->getActionTitle()); + } + + public function testIntroduceParamLabels() + { + $this->assertSame([ + 'attribute_sets' => 'Attribute Sets' + ], $this->model->introduceParamLabels()); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/CartPriceRulesFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/CartPriceRulesFixtureTest.php index 9a871cbd196d2..c8eb60180e843 100755 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/CartPriceRulesFixtureTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/CartPriceRulesFixtureTest.php @@ -1,6 +1,6 @@ fixtureModelMock = $this->getMock(\Magento\Setup\Fixtures\FixtureModel::class, [], [], '', false); + $this->fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); $this->model = new ConfigurableProductsFixture($this->fixtureModelMock); } + /** + * @SuppressWarnings(PHPMD) + */ public function testExecute() { - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); - $contextMock = $this->getMock(\Magento\Framework\Model\ResourceModel\Db\Context::class, [], [], '', false); + $contextMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\Context::class) + ->disableOriginalConstructor() + ->getMock(); $abstractDbMock = $this->getMockForAbstractClass( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, [$contextMock], @@ -46,7 +55,9 @@ public function testExecute() ->method('getAllChildren') ->will($this->returnValue([1])); - $categoryMock = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false); + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); $categoryMock->expects($this->once()) ->method('getResource') ->will($this->returnValue($abstractDbMock)); @@ -60,12 +71,16 @@ public function testExecute() ->method('load') ->willReturnSelf(); - $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) + ->disableOriginalConstructor() + ->getMock(); $storeMock->expects($this->once()) ->method('getRootCategoryId') ->will($this->returnValue([2])); - $websiteMock = $this->getMock(\Magento\Store\Model\Website::class, [], [], '', false); + $websiteMock = $this->getMockBuilder(\Magento\Store\Model\Website::class) + ->disableOriginalConstructor() + ->getMock(); $websiteMock->expects($this->once()) ->method('getCode') ->will($this->returnValue('website_code')); @@ -73,15 +88,18 @@ public function testExecute() ->method('getGroups') ->will($this->returnValue([$storeMock])); - $storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); + $storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManager::class) + ->disableOriginalConstructor() + ->getMock(); $storeManagerMock->expects($this->once()) ->method('getWebsites') ->will($this->returnValue([$websiteMock])); $source = $this->getMockBuilder(Generator::class)->disableOriginalConstructor()->getMock(); - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); - + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); $objectManagerMock->expects($this->at(0)) ->method('get') ->with(\Magento\Store\Model\StoreManager::class) @@ -103,14 +121,61 @@ public function testExecute() $importMock->expects($this->once())->method('validateSource')->with($source)->willReturn(1); $importMock->expects($this->once())->method('importSource')->willReturn(1); + $valuesMap = [ + ['configurable_products', 0, 1], + ['simple_products', 0, 1], + ['search_terms', null, ['search_term' =>[['term' => 'iphone 6', 'count' => '1']]]], + ['configurable_products_variation', 3, 1], + [ + 'search_config', + null, + [ + 'max_amount_of_words_description' => '200', + 'max_amount_of_words_short_description' => '20', + 'min_amount_of_words_description' => '20', + 'min_amount_of_words_short_description' => '5' + ] + ], + ['attribute_sets', + null, + [ + 'attribute_set' => [ + [ + 'name' => 'attribute set name', + 'attributes' => [ + 'attribute' => [ + [ + 'is_required' => 1, + 'is_visible_on_front' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'default_value' => 'yellow1', + 'attribute_code' => 'mycolor', + 'is_searchable' => '1', + 'frontend_label' => 'mycolor', + 'frontend_input' => 'select', + 'options' => [ + 'option' => [ + [ + 'label' => 'yellow1', + 'value' => '' + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + $this->fixtureModelMock ->expects($this->any()) ->method('getValue') - ->willReturnMap([ - ['configurable_products', 0, 1], - ['configurable_products_variation', 3, 1], - ]); - + ->will($this->returnValueMap($valuesMap)); $this->fixtureModelMock ->expects($this->atLeastOnce()) ->method('getObjectManager') @@ -121,11 +186,15 @@ public function testExecute() public function testNoFixtureConfigValue() { - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); $importMock->expects($this->never())->method('validateSource'); $importMock->expects($this->never())->method('importSource'); - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); $objectManagerMock->expects($this->never()) ->method('create') ->with($this->equalTo(\Magento\ImportExport\Model\Import::class)) @@ -151,7 +220,7 @@ public function testGetActionTitle() public function testIntroduceParamLabels() { $this->assertSame([ - 'configurable_products' => 'Configurable products', + 'configurable_products' => 'Configurable products' ], $this->model->introduceParamLabels()); } } diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php index 2ec140b4412ed..4db4438a2a9a9 100644 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/CustomersFixtureTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\Xml\Parser::class, ['load', 'xmlToArray'], [], '', false); - $fileParserMock->expects($this->once())->method('xmlToArray')->willReturn( + $fileParserMock = $this->getMock(\Magento\Framework\Xml\Parser::class, ['getDom', 'xmlToArray'], [], '', false); + $fileParserMock->expects($this->exactly(2))->method('xmlToArray')->willReturn( ['config' => [ 'profile' => ['some_key' => 'some_value']]] ); - $fileParserMock->expects($this->once())->method('load')->with('config.file')->willReturn($fileParserMock); + + $domMock = $this->getMock(\DOMDocument::class, ['load', 'xinclude'], [], '', false); + $domMock->expects($this->once())->method('load')->with('config.file')->willReturn( + $fileParserMock->xmlToArray() + ); + $domMock->expects($this->once())->method('xinclude'); + + $fileParserMock->expects($this->exactly(2))->method('getDom')->willReturn($domMock); + $this->model = new FixtureModel($reindexCommandMock, $fileParserMock); $this->model->loadConfig('config.file'); $this->assertSame('some_value', $this->model->getValue('some_key')); diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/IndexersStatesApplyFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/IndexersStatesApplyFixtureTest.php index 56fa29d6d4b8c..12c4f00ef0e85 100644 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/IndexersStatesApplyFixtureTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/IndexersStatesApplyFixtureTest.php @@ -1,6 +1,6 @@ fixtureModelMock = $this->getMock(\Magento\Setup\Fixtures\FixtureModel::class, [], [], '', false); + $this->fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); $this->model = new SimpleProductsFixture($this->fixtureModelMock); } + /** + * @SuppressWarnings(PHPMD) + */ public function testExecute() { - $storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) + ->disableOriginalConstructor() + ->getMock(); $storeMock->expects($this->once()) ->method('getRootCategoryId') ->willReturn(1); - $websiteMock = $this->getMock(\Magento\Store\Model\Website::class, [], [], '', false); + $websiteMock = $this->getMockBuilder(\Magento\Store\Model\Website::class) + ->disableOriginalConstructor() + ->getMock(); $websiteMock->expects($this->once()) ->method('getCode') ->willReturn('website_code'); @@ -42,14 +51,24 @@ public function testExecute() ->method('getGroups') ->willReturn([$storeMock]); - $storeManagerMock = $this->getMock(\Magento\Store\Model\StoreManager::class, [], [], '', false); + $storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManager::class) + ->disableOriginalConstructor() + ->getMock(); $storeManagerMock->expects($this->once()) ->method('getWebsites') ->willReturn([$websiteMock]); - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $source = $this->getMockBuilder(\Magento\Setup\Model\Generator::class)->disableOriginalConstructor()->getMock(); + + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); + $importMock->expects($this->once())->method('validateSource')->with($source)->willReturn(1); + $importMock->expects($this->once())->method('importSource')->willReturn(1); - $contextMock = $this->getMock(\Magento\Framework\Model\ResourceModel\Db\Context::class, [], [], '', false); + $contextMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\Context::class) + ->disableOriginalConstructor() + ->getMock(); $abstractDbMock = $this->getMockForAbstractClass( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, [$contextMock], @@ -63,7 +82,9 @@ public function testExecute() ->method('getAllChildren') ->will($this->returnValue([1])); - $categoryMock = $this->getMock(\Magento\Catalog\Model\Category::class, [], [], '', false); + $categoryMock = $this->getMockBuilder(\Magento\Catalog\Model\Category::class) + ->disableOriginalConstructor() + ->getMock(); $categoryMock->expects($this->once()) ->method('getResource') ->willReturn($abstractDbMock); @@ -77,35 +98,81 @@ public function testExecute() ->method('getName') ->willReturn('category_name'); - $valueMap = [ - [ - \Magento\ImportExport\Model\Import::class, - [ - 'data' => [ - 'entity' => 'catalog_product', - 'behavior' => 'append', - 'validation_strategy' => 'validation-stop-on-errors' - ] - ], - $importMock - ], - [\Magento\Store\Model\StoreManager::class, [], $storeManagerMock] - ]; - - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); - $objectManagerMock->expects($this->exactly(2)) + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock->expects($this->at(0)) ->method('create') - ->will($this->returnValueMap($valueMap)); - $objectManagerMock->expects($this->once()) + ->with(\Magento\Store\Model\StoreManager::class) + ->willReturn($storeManagerMock); + $objectManagerMock->expects($this->at(1)) ->method('get') ->willReturn($categoryMock); + $objectManagerMock->expects($this->at(2)) + ->method('create') + ->with(\Magento\Setup\Model\Generator::class) + ->willReturn($source); + $objectManagerMock->expects($this->at(3)) + ->method('create') + ->with(\Magento\ImportExport\Model\Import::class) + ->willReturn($importMock); + $valuesMap = [ + ['simple_products', 0, 1], + ['configurable_products', 0, 1], + ['search_terms', null, ['search_term' =>[['term' => 'iphone 6', 'count' => '1']]]], + [ + 'search_config', + null, + [ + 'max_amount_of_words_description' => '200', + 'max_amount_of_words_short_description' => '20', + 'min_amount_of_words_description' => '20', + 'min_amount_of_words_short_description' => '5' + ] + ], + [ + 'attribute_sets', + null, + [ + 'attribute_set' => [ + [ + 'name' => 'attribute set name', + 'attributes' => [ + 'attribute' => [ + [ + 'is_required' => 1, + 'is_visible_on_front' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'default_value' => 'yellow1', + 'attribute_code' => 'mycolor', + 'is_searchable' => '1', + 'frontend_label' => 'mycolor', + 'frontend_input' => 'select', + 'options' => [ + 'option' => [ + [ + 'label' => 'yellow1', + 'value' => '' + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; $this->fixtureModelMock - ->expects($this->once()) + ->expects($this->any()) ->method('getValue') - ->willReturn(1); + ->will($this->returnValueMap($valuesMap)); $this->fixtureModelMock - ->expects($this->exactly(3)) + ->expects($this->any()) ->method('getObjectManager') ->willReturn($objectManagerMock); @@ -114,11 +181,15 @@ public function testExecute() public function testNoFixtureConfigValue() { - $importMock = $this->getMock(\Magento\ImportExport\Model\Import::class, [], [], '', false); + $importMock = $this->getMockBuilder(\Magento\ImportExport\Model\Import::class) + ->disableOriginalConstructor() + ->getMock(); $importMock->expects($this->never())->method('validateSource'); $importMock->expects($this->never())->method('importSource'); - $objectManagerMock = $this->getMock(\Magento\Framework\ObjectManager\ObjectManager::class, [], [], '', false); + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); $objectManagerMock->expects($this->never()) ->method('create') ->with($this->equalTo(\Magento\ImportExport\Model\Import::class)) @@ -129,7 +200,7 @@ public function testNoFixtureConfigValue() ->method('getObjectManager') ->will($this->returnValue($objectManagerMock)); $this->fixtureModelMock - ->expects($this->once()) + ->expects($this->any()) ->method('getValue') ->willReturn(false); diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/StoresFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/StoresFixtureTest.php index 7c1c37cc81a5e..cb5cb9fbd2180 100644 --- a/setup/src/Magento/Setup/Test/Unit/Fixtures/StoresFixtureTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/StoresFixtureTest.php @@ -1,6 +1,6 @@ '%s', 'name' => 'Static', - 'calculated' => function ($index) { - return $index * 10; + 'calculated' => function ($index, $generatedKey) { + return $index * 10 + $generatedKey; }, ], [ @@ -53,7 +53,7 @@ public function patternDataProvider() 'name' => 'yyy %s' ], ], - 'ecpectedCount' => 3, + 'expectedCount' => 3, 'expectedRowsResult' => [ ['id' => '1', 'name' => 'Static', 'calculated' => 10], ['id' => '', 'name' => 'xxx 1', 'calculated' => ''], @@ -68,7 +68,7 @@ public function patternDataProvider() 'calculated' => 'calc %s', ], ], - 'ecpectedCount' => 1, + 'expectedCount' => 1, 'expectedRowsResult' => [ ['id' => '1', 'name' => 'Dynamic 1', 'calculated' => 'calc 1'], ], diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php index 033ab78c69cd0..6c5b7ce339613 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php @@ -1,6 +1,6 @@ assertSame('Encryption key', $options[0]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\SelectConfigOption::class, $options[1]); $this->assertSame('Session save handler', $options[1]->getDescription()); - $this->assertInstanceOf(\Magento\Framework\Setup\Option\SelectConfigOption::class, $options[2]); - $this->assertSame('Type of definitions used by Object Manager', $options[2]->getDescription()); + $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[2]); + $this->assertSame('Database server host', $options[2]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[3]); - $this->assertSame('Database server host', $options[3]->getDescription()); + $this->assertSame('Database name', $options[3]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[4]); - $this->assertSame('Database name', $options[4]->getDescription()); + $this->assertSame('Database server username', $options[4]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[5]); - $this->assertSame('Database server username', $options[5]->getDescription()); + $this->assertSame('Database server engine', $options[5]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[6]); - $this->assertSame('Database server engine', $options[6]->getDescription()); + $this->assertSame('Database server password', $options[6]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[7]); - $this->assertSame('Database server password', $options[7]->getDescription()); + $this->assertSame('Database table prefix', $options[7]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[8]); - $this->assertSame('Database table prefix', $options[8]->getDescription()); + $this->assertSame('Database type', $options[8]->getDescription()); $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[9]); - $this->assertSame('Database type', $options[9]->getDescription()); - $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[10]); - $this->assertSame('Database initial set of commands', $options[10]->getDescription()); - $this->assertInstanceOf(\Magento\Framework\Setup\Option\FlagConfigOption::class, $options[11]); + $this->assertSame('Database initial set of commands', $options[9]->getDescription()); + $this->assertInstanceOf(\Magento\Framework\Setup\Option\FlagConfigOption::class, $options[10]); $this->assertSame( 'If specified, then db connection validation will be skipped', - $options[11]->getDescription() + $options[10]->getDescription() ); - $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[12]); - $this->assertSame('http Cache hosts', $options[12]->getDescription()); - $this->assertEquals(13, count($options)); + $this->assertInstanceOf(\Magento\Framework\Setup\Option\TextConfigOption::class, $options[11]); + $this->assertSame('http Cache hosts', $options[11]->getDescription()); + $this->assertEquals(12, count($options)); } public function testCreateOptions() diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Cron/Helper/ModuleUninstallTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Cron/Helper/ModuleUninstallTest.php index 4fe96a37c724a..143e0b4e8c1da 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Cron/Helper/ModuleUninstallTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/Cron/Helper/ModuleUninstallTest.php @@ -1,6 +1,6 @@ generate($wordCount, $wordCount); + + $found = false; + foreach ($data as $word) { + $found = (strpos($result, $word[0]) !== false) || $found; + } + $this->assertTrue($found); + $this->assertEquals($wordCount, count(explode(" ", $result))); + } + + public function testGenerateWithKey() + { + $key = 'generate-test'; + + $data = file(__DIR__ . self::PATH_TO_CSV_FILE); + $wordCount = mt_rand(1, count($data)); + $model = new DataGenerator(__DIR__ . self::PATH_TO_CSV_FILE); + $result = $model->generate($wordCount, $wordCount, $key); + + $foundResult = $model->generate($wordCount, $wordCount, $key); + + $this->assertEquals($wordCount, count(explode(" ", $result))); + $this->assertEquals($result, $foundResult); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/DateTime/DateTimeProviderTest.php b/setup/src/Magento/Setup/Test/Unit/Model/DateTime/DateTimeProviderTest.php index 05992d69495f3..ffde07483b848 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/DateTime/DateTimeProviderTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/DateTime/DateTimeProviderTest.php @@ -1,6 +1,6 @@ expects($this->any())->method('getAvailableTypes')->willReturn(['foo', 'bar']); $cacheManager->expects($this->once())->method('setEnabled')->willReturn(['foo', 'bar']); $cacheManager->expects($this->any())->method('clean'); - $appState = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject( - \Magento\Framework\App\State::class - ); + $appState = $this->getMockBuilder(\Magento\Framework\App\State::class) + ->disableOriginalConstructor() + ->disableArgumentCloning() + ->getMock(); + $appState->expects($this->once()) + ->method('setAreaCode') + ->with(\Magento\Framework\App\Area::AREA_GLOBAL); $this->setupFactory->expects($this->atLeastOnce())->method('create')->with($resource)->willReturn($setup); $this->dataSetupFactory->expects($this->atLeastOnce())->method('create')->willReturn($dataSetup); $this->objectManager->expects($this->any()) diff --git a/setup/src/Magento/Setup/Test/Unit/Model/LicenseTest.php b/setup/src/Magento/Setup/Test/Unit/Model/LicenseTest.php index ed8f3efccb7a1..d8843dd2c97a4 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/LicenseTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/LicenseTest.php @@ -1,6 +1,6 @@ getComposerInformation(); - $timeZoneProvider = $this->getMock(\Magento\Setup\Model\DateTime\TimeZoneProvider::class, [], [], '', false); + $this->composerInformation = $this->getComposerInformation(); + $this->timeZoneProvider = $this->getMockBuilder(\Magento\Setup\Model\DateTime\TimeZoneProvider::class) + ->disableOriginalConstructor() + ->getMock(); $timeZone = $this->getMock(\Magento\Framework\Stdlib\DateTime\Timezone::class, [], [], '', false); - $timeZoneProvider->expects($this->any())->method('get')->willReturn($timeZone); - $packagesAuth = $this->getMock(\Magento\Setup\Model\PackagesAuth::class, [], [], '', false); - $filesystem = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); - $objectManagerProvider = $this->getMock(\Magento\Setup\Model\ObjectManagerProvider::class, [], [], '', false); + $this->timeZoneProvider->expects($this->any())->method('get')->willReturn($timeZone); + $this->packagesAuth = $this->getMock(\Magento\Setup\Model\PackagesAuth::class, [], [], '', false); + $this->filesystem = $this->getMock(\Magento\Framework\Filesystem::class, [], [], '', false); + $this->objectManagerProvider = $this->getMockBuilder(\Magento\Setup\Model\ObjectManagerProvider::class) + ->disableOriginalConstructor() + ->getMock(); $objectManager = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class); - $applicationFactory = $this->getMock( - \Magento\Framework\Composer\MagentoComposerApplicationFactory::class, - [], - [], - '', - false - ); + $appFactory = $this->getMockBuilder(\Magento\Framework\Composer\MagentoComposerApplicationFactory::class) + ->disableOriginalConstructor() + ->getMock(); $application = $this->getMock(\Magento\Composer\MagentoComposerApplication::class, [], [], '', false); $application->expects($this->any()) ->method('runComposerCommand') - ->willReturn('versions: 2.0.1'); - $applicationFactory->expects($this->any())->method('create')->willReturn($application); + ->willReturnMap([ + [ + [ + PackagesData::PARAM_COMMAND => PackagesData::COMPOSER_SHOW, + PackagesData::PARAM_PACKAGE => 'magento/package-1', + PackagesData::PARAM_AVAILABLE => true, + ], + null, + 'versions: 2.0.1' + ], + [ + [ + PackagesData::PARAM_COMMAND => PackagesData::COMPOSER_SHOW, + PackagesData::PARAM_PACKAGE => 'magento/package-2', + PackagesData::PARAM_AVAILABLE => true, + ], + null, + 'versions: 2.0.1' + ], + [ + [ + PackagesData::PARAM_COMMAND => PackagesData::COMPOSER_SHOW, + PackagesData::PARAM_PACKAGE => 'partner/package-3', + PackagesData::PARAM_AVAILABLE => true, + ], + null, + 'versions: 3.0.1' + ], + ]); + $appFactory->expects($this->any())->method('create')->willReturn($application); $objectManager->expects($this->any()) ->method('get') ->with(\Magento\Framework\Composer\MagentoComposerApplicationFactory::class) - ->willReturn($applicationFactory); - $objectManagerProvider->expects($this->any())->method('get')->willReturn($objectManager); + ->willReturn($appFactory); + $this->objectManagerProvider->expects($this->any())->method('get')->willReturn($objectManager); $directoryWrite = $this->getMockForAbstractClass(\Magento\Framework\Filesystem\Directory\WriteInterface::class); $directoryRead = $this->getMockForAbstractClass(\Magento\Framework\Filesystem\Directory\ReadInterface::class); - $filesystem->expects($this->any())->method('getDirectoryRead')->will($this->returnValue($directoryRead)); - $filesystem->expects($this->any()) + $this->filesystem->expects($this->any())->method('getDirectoryRead')->will($this->returnValue($directoryRead)); + $this->filesystem->expects($this->any()) ->method('getDirectoryWrite') ->will($this->returnValue($directoryWrite)); $directoryWrite->expects($this->any())->method('isExist')->willReturn(true); @@ -81,32 +139,41 @@ public function setUp() . '}}}' ); - $typeMapper = $this->getMockBuilder(\Magento\Setup\Model\Grid\TypeMapper::class) + $this->typeMapper = $this->getMockBuilder(\Magento\Setup\Model\Grid\TypeMapper::class) ->disableOriginalConstructor() ->getMock(); - $typeMapper->expects(static::any()) + $this->typeMapper->expects(static::any()) ->method('map') ->willReturnMap([ [ComposerInformation::MODULE_PACKAGE_TYPE, \Magento\Setup\Model\Grid\TypeMapper::MODULE_PACKAGE_TYPE], ]); + $this->createPackagesData(); + } + + private function createPackagesData() + { $this->packagesData = new PackagesData( - $composerInformation, - $timeZoneProvider, - $packagesAuth, - $filesystem, - $objectManagerProvider, - $typeMapper + $this->composerInformation, + $this->timeZoneProvider, + $this->packagesAuth, + $this->filesystem, + $this->objectManagerProvider, + $this->typeMapper ); } /** + * @param array $requiredPackages + * @param array $installedPackages + * @param array $repo * @return ComposerInformation|MockObject */ - private function getComposerInformation() + private function getComposerInformation($requiredPackages = [], $installedPackages = [], $repo = []) { $composerInformation = $this->getMock(ComposerInformation::class, [], [], '', false); $composerInformation->expects($this->any())->method('getInstalledMagentoPackages')->willReturn( + $installedPackages ?: [ 'magento/package-1' => [ 'name' => 'magento/package-1', @@ -117,21 +184,30 @@ private function getComposerInformation() 'name' => 'magento/package-2', 'type' => 'magento2-module', 'version'=> '1.0.1' - ] + ], + 'partner/package-3' => [ + 'name' => 'partner/package-3', + 'type' => 'magento2-module', + 'version'=> '3.0.0' + ], ] ); $composerInformation->expects($this->any())->method('getRootRepositories') - ->willReturn(['repo1', 'repo2']); + ->willReturn($repo ?: ['repo1', 'repo2']); $composerInformation->expects($this->any())->method('getPackagesTypes') ->willReturn(['magento2-module']); $rootPackage = $this->getMock(RootPackage::class, [], ['magento/project', '2.1.0', '2']); $rootPackage->expects($this->any()) ->method('getRequires') - ->willReturn([ - 'magento/package-1' => '1.0.0', - 'magento/package-2' => '1.0.1' - ]); + ->willReturn( + $requiredPackages ?: + [ + 'magento/package-1' => '1.0.0', + 'magento/package-2' => '1.0.1', + 'partner/package-3' => '3.0.0', + ] + ); $composerInformation->expects($this->any()) ->method('getRootPackage') ->willReturn($rootPackage); @@ -146,19 +222,57 @@ public function testSyncPackagesData() $this->assertArrayHasKey('date', $latestData['lastSyncDate']); $this->assertArrayHasKey('time', $latestData['lastSyncDate']); $this->assertArrayHasKey('packages', $latestData); - $this->assertSame(2, count($latestData['packages'])); - $this->assertSame(2, $latestData['countOfUpdate']); + $this->assertSame(3, count($latestData['packages'])); + $this->assertSame(3, $latestData['countOfUpdate']); $this->assertArrayHasKey('installPackages', $latestData); $this->assertSame(1, count($latestData['installPackages'])); $this->assertSame(1, $latestData['countOfInstall']); } - public function testGetPackagesForUpdate() + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Couldn't get available versions for package partner/package-4 + */ + public function testGetPackagesForUpdateWithException() { + $requiredPackages = [ + 'partner/package-4' => '4.0.4', + ]; + $installedPackages = [ + 'partner/package-4' => [ + 'name' => 'partner/package-4', + 'type' => 'magento2-module', + 'version'=> '4.0.4' + ], + ]; + $this->composerInformation = $this->getComposerInformation($requiredPackages, $installedPackages); + $this->createPackagesData(); + $this->packagesData->getPackagesForUpdate(); + } + + public function testPackagesForUpdateFromJson() + { + $this->composerInformation = $this->getComposerInformation([], [], ['https://repo1']); + $this->packagesAuth->expects($this->atLeastOnce()) + ->method('getCredentialBaseUrl') + ->willReturn('repo1'); + $this->createPackagesData(); $packages = $this->packagesData->getPackagesForUpdate(); $this->assertEquals(2, count($packages)); $this->assertArrayHasKey('magento/package-1', $packages); + $this->assertArrayHasKey('partner/package-3', $packages); + $firstPackage = array_values($packages)[0]; + $this->assertArrayHasKey('latestVersion', $firstPackage); + $this->assertArrayHasKey('versions', $firstPackage); + } + + public function testGetPackagesForUpdate() + { + $packages = $this->packagesData->getPackagesForUpdate(); + $this->assertEquals(3, count($packages)); + $this->assertArrayHasKey('magento/package-1', $packages); $this->assertArrayHasKey('magento/package-2', $packages); + $this->assertArrayHasKey('partner/package-3', $packages); $firstPackage = array_values($packages)[0]; $this->assertArrayHasKey('latestVersion', $firstPackage); $this->assertArrayHasKey('versions', $firstPackage); @@ -167,9 +281,10 @@ public function testGetPackagesForUpdate() public function testGetInstalledPackages() { $installedPackages = $this->packagesData->getInstalledPackages(); - $this->assertEquals(2, count($installedPackages)); + $this->assertEquals(3, count($installedPackages)); $this->assertArrayHasKey('magento/package-1', $installedPackages); $this->assertArrayHasKey('magento/package-2', $installedPackages); + $this->assertArrayHasKey('partner/package-3', $installedPackages); } public function testGetMetaPackagesMap() diff --git a/setup/src/Magento/Setup/Test/Unit/Model/PayloadValidatorTest.php b/setup/src/Magento/Setup/Test/Unit/Model/PayloadValidatorTest.php index 2b1d8529d7818..27f6ec8151e6b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/PayloadValidatorTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/PayloadValidatorTest.php @@ -1,6 +1,6 @@ $xdebugMessage, 'error' => false, ], - ] + 'missed_function_imagecreatefromjpeg' => [ + 'message' => 'You must have installed GD library with --with-jpeg-dir=DIR option.', + 'helpUrl' => 'http://php.net/manual/en/image.installation.php', + 'error' => false, + ], + ], ]; if (!$this->isPhp7OrHhvm()) { $this->setUpNoPrettyVersionParser(); @@ -261,8 +266,13 @@ public function testCheckPhpSettingsFailed() 'xdebug_max_nesting_level' => [ 'message' => $xdebugMessage, 'error' => true, - ] - ] + ], + 'missed_function_imagecreatefromjpeg' => [ + 'message' => 'You must have installed GD library with --with-jpeg-dir=DIR option.', + 'helpUrl' => 'http://php.net/manual/en/image.installation.php', + 'error' => false, + ], + ], ]; if (!$this->isPhp7OrHhvm()) { $this->setUpNoPrettyVersionParser(); @@ -301,6 +311,13 @@ public function testCheckPhpSettingsNoXDebug() ] ]; } + + $expected['data']['missed_function_imagecreatefromjpeg'] = [ + 'message' => 'You must have installed GD library with --with-jpeg-dir=DIR option.', + 'helpUrl' => 'http://php.net/manual/en/image.installation.php', + 'error' => false, + ]; + $this->assertEquals($expected, $this->phpReadinessCheck->checkPhpSettings()); } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/StoreConfigurationDataMapperTest.php b/setup/src/Magento/Setup/Test/Unit/Model/StoreConfigurationDataMapperTest.php index 67792c93ee71d..902763d8821b9 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/StoreConfigurationDataMapperTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/StoreConfigurationDataMapperTest.php @@ -1,6 +1,6 @@ '1.2.0', 'name' => 'Version 1.2.0 EE (latest)', - 'package' => 'magento/product-enterprise-edition', + 'package' => SystemPackage::EDITION_ENTERPRISE, 'stable' => true, 'current' => false, ], [ 'id' => '1.2.0', 'name' => 'Version 1.2.0 CE (latest)', - 'package' => 'magento/product-community-edition', + 'package' => SystemPackage::EDITION_COMMUNITY, 'stable' => true, 'current' => false, ], [ 'id' => '1.1.0', 'name' => 'Version 1.1.0 EE', - 'package' => 'magento/product-enterprise-edition', + 'package' => SystemPackage::EDITION_ENTERPRISE, 'stable' => true, 'current' => false, ], [ 'id' => '1.1.0', 'name' => 'Version 1.1.0 CE', - 'package' => 'magento/product-community-edition', + 'package' => SystemPackage::EDITION_COMMUNITY, 'stable' => true, 'current' => false, ], [ 'id' => '1.1.0-RC1', 'name' => 'Version 1.1.0-RC1 EE (unstable version)', - 'package' => 'magento/product-enterprise-edition', + 'package' => SystemPackage::EDITION_ENTERPRISE, 'stable' => false, 'current' => false, ], [ 'id' => '1.1.0-RC1', 'name' => 'Version 1.1.0-RC1 CE (unstable version)', - 'package' => 'magento/product-community-edition', + 'package' => SystemPackage::EDITION_COMMUNITY, 'stable' => false, 'current' => false, ], [ 'id' => '1.0.0', 'name' => 'Version 1.0.0 EE', - 'package' => 'magento/product-enterprise-edition', + 'package' => SystemPackage::EDITION_ENTERPRISE, 'stable' => true, 'current' => true, ], [ 'id' => '1.0.0', 'name' => 'Version 1.0.0 CE', - 'package' => 'magento/product-community-edition', + 'package' => SystemPackage::EDITION_COMMUNITY, 'stable' => true, 'current' => true, ], @@ -147,9 +148,9 @@ public function setUp() public function testGetPackageVersions() { $communityPackage = $this->getMock(\Composer\Package\Package::class, [], [], '', false); - $communityPackage->expects($this->once())->method('getName')->willReturn('magento/product-community-edition'); + $communityPackage->expects($this->once())->method('getName')->willReturn(SystemPackage::EDITION_COMMUNITY); $enterprisePackage = $this->getMock(\Composer\Package\Package::class, [], [], '', false); - $enterprisePackage->expects($this->once())->method('getName')->willReturn('magento/product-enterprise-edition'); + $enterprisePackage->expects($this->once())->method('getName')->willReturn(SystemPackage::EDITION_ENTERPRISE); $this->composerInformation->expects($this->any())->method('isSystemPackage')->willReturn(true); $this->composerInformation->expects($this->once())->method('isPackageInComposerJson')->willReturn(true); $this->repository @@ -176,43 +177,62 @@ public function testGetPackageVersions() $this->systemPackage = new SystemPackage($this->composerAppFactory, $this->composerInformation); - $this->infoCommand->expects($this->at(0)) + $this->infoCommand->expects($this->any()) ->method('run') - ->with('magento/product-community-edition') - ->willReturn( + ->willReturnMap([ [ - 'name' => 'magento/product-community-edition', - 'description' => 'eCommerce Platform for Growth (Enterprise Edition)', - 'keywords' => '', - 'versions' => '1.2.0, 1.1.0, 1.1.0-RC1, * 1.0.0', - 'type' => 'metapackage', - 'license' => 'OSL-3.0, AFL-3.0', - 'source' => '[]', - 'names' => 'magento/product-community-edition', - 'current_version' => '1.0.0', - 'available_versions' => [1 => '1.2.0', 2 => '1.1.0', 3 => '1.1.0-RC1', 4 => '1.0.0'], - 'new_versions' => ['1.2.0', '1.1.0', '1.1.0-RC1'], - ] - ); - - $this->infoCommand->expects($this->at(1)) - ->method('run') - ->with('magento/product-enterprise-edition') - ->willReturn( + SystemPackage::EDITION_COMMUNITY, + false, + [ + 'name' => SystemPackage::EDITION_COMMUNITY, + 'description' => 'eCommerce Platform for Growth (Enterprise Edition)', + 'keywords' => '', + 'versions' => '1.2.0, 1.1.0, 1.1.0-RC1, * 1.0.0', + 'type' => 'metapackage', + 'license' => 'OSL-3.0, AFL-3.0', + 'source' => '[]', + 'names' => SystemPackage::EDITION_COMMUNITY, + 'current_version' => '1.0.0', + InfoCommand::AVAILABLE_VERSIONS => [1 => '1.2.0', 2 => '1.1.0', 3 => '1.1.0-RC1', 4 => '1.0.0'], + 'new_versions' => ['1.2.0', '1.1.0', '1.1.0-RC1'], + ], + ], + [ + SystemPackage::EDITION_ENTERPRISE, + false, + [ + 'name' => SystemPackage::EDITION_ENTERPRISE, + 'description' => 'eCommerce Platform for Growth (Enterprise Edition)', + 'keywords' => '', + 'versions' => '1.2.0, 1.1.0, 1.1.0-RC1, * 1.0.0', + 'type' => 'metapackage', + 'license' => 'OSL-3.0, AFL-3.0', + 'source' => '[]', + 'names' => SystemPackage::EDITION_ENTERPRISE, + 'current_version' => '1.0.0', + InfoCommand::AVAILABLE_VERSIONS => [1 => '1.2.0', 2 => '1.1.0', 3 => '1.1.0-RC1', 4 => '1.0.0'], + 'new_versions' => ['1.2.0', '1.1.0', '1.1.0-RC1'], + ], + + ], [ - 'name' => 'magento/product-enterprise-edition', - 'description' => 'eCommerce Platform for Growth (Enterprise Edition)', - 'keywords' => '', - 'versions' => '1.2.0, 1.1.0, 1.1.0-RC1, * 1.0.0', - 'type' => 'metapackage', - 'license' => 'OSL-3.0, AFL-3.0', - 'source' => '[]', - 'names' => 'magento/product-enterprise-edition', - 'current_version' => '1.0.0', - 'available_versions' => [1 => '1.2.0', 2 => '1.1.0', 3 => '1.1.0-RC1', 4 => '1.0.0'], - 'new_versions' => ['1.2.0', '1.1.0', '1.1.0-RC1'], - ] - ); + + SystemPackage::EDITION_B2B, + false, + [ + 'name' => SystemPackage::EDITION_B2B, + 'description' => 'eCommerce Platform for Growth (B2B Edition)', + 'keywords' => '', + 'versions' => '1.2.0, 1.1.0, 1.1.0-RC1, * 1.0.0', + 'type' => 'metapackage', + 'license' => 'OSL-3.0, AFL-3.0', + 'source' => '[]', + 'names' => SystemPackage::EDITION_B2B, + InfoCommand::AVAILABLE_VERSIONS => [], + 'new_versions' => ['1.2.0', '1.1.0', '1.1.0-RC1'], + ], + ], + ]); $this->assertEquals($this->expectedPackages, $this->systemPackage->getPackageVersions()); } @@ -254,8 +274,8 @@ public function testGetPackageVersionsFailed() $communityPackage = $this->getMock(\Composer\Package\Package::class, [], [], '', false); $enterprisePackage = $this->getMock(\Composer\Package\Package::class, [], [], '', false); - $communityPackage->expects($this->once())->method('getName')->willReturn('magento/product-community-edition'); - $enterprisePackage->expects($this->once())->method('getName')->willReturn('magento/product-enterprise-edition'); + $communityPackage->expects($this->once())->method('getName')->willReturn(SystemPackage::EDITION_COMMUNITY); + $enterprisePackage->expects($this->once())->method('getName')->willReturn(SystemPackage::EDITION_ENTERPRISE); $this->composerInformation->expects($this->any())->method('isSystemPackage')->willReturn(true); $this->composerInformation->expects($this->once())->method('isPackageInComposerJson')->willReturn(true); @@ -281,7 +301,7 @@ public function testGetPackageVersionsFailed() $this->infoCommand->expects($this->once()) ->method('run') - ->with('magento/product-community-edition') + ->with(SystemPackage::EDITION_COMMUNITY) ->willReturn(false); $this->systemPackage->getPackageVersions(); @@ -301,8 +321,8 @@ public function testGetAllowedEnterpriseVersions($ceCurrentVersion, $expectedRes $this->systemPackage = new SystemPackage($this->composerAppFactory, $this->composerInformation); $this->infoCommand->expects($this->once()) ->method('run') - ->with('magento/product-enterprise-edition') - ->willReturn(['available_versions' => ['1.0.0', '1.0.1', '1.0.2']]); + ->with(SystemPackage::EDITION_ENTERPRISE) + ->willReturn([InfoCommand::AVAILABLE_VERSIONS => ['1.0.0', '1.0.1', '1.0.2']]); $require = $this->getMock(\Composer\Package\Link::class, [], [], '', false); $constraintMock = $this->getMock(\Composer\Semver\Constraint\Constraint::class, [], [], '', false); $constraintMock->expects($this->any())->method('getPrettyString') @@ -313,13 +333,46 @@ public function testGetAllowedEnterpriseVersions($ceCurrentVersion, $expectedRes $this->composerInformation->expects($this->any()) ->method('getPackageRequirements') - ->willReturn(['magento/product-community-edition' => $require]); + ->willReturn([SystemPackage::EDITION_COMMUNITY => $require]); $this->assertEquals( $expectedResult, $this->systemPackage->getAllowedEnterpriseVersions($ceCurrentVersion) ); } + /** + * @param string $eeCurrentVersion + * @param array $expectedResult + * + * @dataProvider getAllowedB2bVersionsDataProvider + */ + public function testGetAllowedB2bVersions($eeCurrentVersion, $expectedResult) + { + $this->composerAppFactory->expects($this->once()) + ->method('createInfoCommand') + ->willReturn($this->infoCommand); + $this->systemPackage = new SystemPackage($this->composerAppFactory, $this->composerInformation); + $this->infoCommand->expects($this->once()) + ->method('run') + ->with(SystemPackage::EDITION_B2B) + ->willReturn([InfoCommand::AVAILABLE_VERSIONS => ['1.0.0', '1.0.1', '1.0.2']]); + $require = $this->getMock(\Composer\Package\Link::class, [], [], '', false); + $constraintMock = $this->getMock(\Composer\Semver\Constraint\Constraint::class, [], [], '', false); + $constraintMock->expects($this->any())->method('getPrettyString') + ->willReturn('1.0.1'); + $require->expects($this->any()) + ->method('getConstraint') + ->willReturn($constraintMock); + + $this->composerInformation->expects($this->any()) + ->method('getPackageRequirements') + ->willReturn([SystemPackage::EDITION_ENTERPRISE => $require]); + $this->assertEquals( + $expectedResult, + $this->systemPackage->getAllowedB2BVersions($eeCurrentVersion) + ); + } + /** * @return array */ @@ -327,30 +380,68 @@ public function getAllowedEnterpriseVersionsDataProvider() { return [ ['2.0.0', []], - ['1.0.0', [ + [ + '1.0.0', [ - 'package' => 'magento/product-enterprise-edition', - 'versions' => [ - [ - 'id' => '1.0.2', - 'name' => 'Version 1.0.2 EE (latest)', - 'current' => false, - ], - [ - 'id' => '1.0.1', - 'name' => 'Version 1.0.1 EE', - 'current' => false, + [ + 'package' => SystemPackage::EDITION_ENTERPRISE, + 'versions' => [ + [ + 'id' => '1.0.2', + 'name' => 'Version 1.0.2 EE (latest)', + 'current' => false, + ], + [ + 'id' => '1.0.1', + 'name' => 'Version 1.0.1 EE', + 'current' => false, + ], + [ + + 'id' => '1.0.0', + 'name' => 'Version 1.0.0 EE', + 'current' => false, + ], ], - [ + ], + ], + ], + ]; + } - 'id' => '1.0.0', - 'name' => 'Version 1.0.0 EE', - 'current' => false, + /** + * @return array + */ + public function getAllowedB2bVersionsDataProvider() + { + return [ + ['2.0.0', []], + [ + '1.0.0', + [ + [ + 'package' => SystemPackage::EDITION_B2B, + 'versions' => [ + [ + 'id' => '1.0.2', + 'name' => 'Version 1.0.2 B2B (latest)', + 'current' => false, + ], + [ + 'id' => '1.0.1', + 'name' => 'Version 1.0.1 B2B', + 'current' => false, + ], + [ + + 'id' => '1.0.0', + 'name' => 'Version 1.0.0 B2B', + 'current' => false, + ], ], ], ], ], - ], ]; } } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ThemeDependencyCheckerFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ThemeDependencyCheckerFactoryTest.php index a26d5eb0f8867..4f76c6b0a830d 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ThemeDependencyCheckerFactoryTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ThemeDependencyCheckerFactoryTest.php @@ -1,6 +1,6 @@ assertEquals([], $returnValue->getData()); } - public function testCreateDefinitionsConfig() - { - $testData = [ConfigOptionsListConstants::INPUT_KEY_DEFINITION_FORMAT => 'test-format']; - $returnValue = $this->configGeneratorObject->createDefinitionsConfig($testData); - $this->assertEquals(ConfigFilePool::APP_ENV, $returnValue->getFileKey()); - $this->assertEquals(['definition' => ['format' => 'test-format']], $returnValue->getData()); - } - public function testCreateDbConfig() { $testData = [ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/ConnectionFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/ConnectionFactoryTest.php index 8b887ab7ba002..4c21ce39cdfb6 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/ConnectionFactoryTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/ConnectionFactoryTest.php @@ -1,6 +1,6 @@ classReaderMock, $this->classesScanner, $this->validatorMock, - '/var/generation' + '/generated/code' ); } @@ -111,7 +111,7 @@ public function testGetList() public function testGetListNoValidation() { - $path = '/var/generation'; + $path = '/generated/code'; $classes = ['NameSpace1\ClassName1', 'NameSpace1\ClassName2']; diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/InterceptionsTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/InterceptionsTest.php index 212575e644d7c..733ba0b85866e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/InterceptionsTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/InterceptionsTest.php @@ -1,6 +1,6 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/di.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/di.xml index 47deb25b5070d..0762ca67ec894 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/di.xml +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/di.xml @@ -1,7 +1,7 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/source/PhpExt.php/content b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/source/PhpExt.php/content index 3c2daa452ee8d..af373f0f2eddd 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/source/PhpExt.php/content +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/source/PhpExt.php/content @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/view/frontend/default.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/view/frontend/default.xml index 119ace1d0e356..2dd9e4557d316 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/view/frontend/default.xml +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/view/frontend/default.xml @@ -1,7 +1,7 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/design/adminhtml/default/backend/layout.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/design/adminhtml/default/backend/layout.xml index a8096b9620b85..0a9bcfa548481 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/design/adminhtml/default/backend/layout.xml +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/design/adminhtml/default/backend/layout.xml @@ -1,7 +1,7 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/additional.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/additional.xml index a8096b9620b85..0a9bcfa548481 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/additional.xml +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/additional.xml @@ -1,7 +1,7 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/config.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/config.xml index 20a064f70bc1b..828f16428a58d 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/config.xml +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/config.xml @@ -1,7 +1,7 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/di/config.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/di/config.xml index 17af1192e5a70..77251c257c8ee 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/di/config.xml +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/di/config.xml @@ -1,7 +1,7 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/extension_attributes.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/extension_attributes.xml index e79052491cbc4..14e5c0662ef44 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/extension_attributes.xml +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/extension_attributes.xml @@ -1,7 +1,7 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/ContextTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/ContextTest.php index fa9f915de9e8c..331d464e45785 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/I18n/ContextTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/ContextTest.php @@ -1,6 +1,6 @@ componentRegistrar->expects($this->any()) ->method('getPaths') - ->will($this->returnValueMap($pathValues)); + ->willReturnMap($pathValues); $this->context = new Context($this->componentRegistrar); $this->assertEquals($context, $this->context->getContextByPath($path)); } @@ -108,10 +108,8 @@ public function testBuildPathToLocaleDirectoryByContext($path, $context, $regist $paths[$module[1]] = $module[2]; } $this->componentRegistrar->expects($this->any()) - ->method('getPaths') - ->with(ComponentRegistrar::MODULE) - ->willReturn($paths); - $this->componentRegistrar->expects($this->any())->method('getPath')->will($this->returnValueMap($registrar)); + ->method('getPath') + ->willReturnMap($registrar); $this->context = new Context($this->componentRegistrar); $this->assertEquals($path, $this->context->buildPathToLocaleDirectoryByContext($context[0], $context[1])); } @@ -127,7 +125,22 @@ public function dataProviderPathToLocaleDirectoryByContext() [Context::CONTEXT_TYPE_MODULE, 'Magento_Module'], [[ComponentRegistrar::MODULE, 'Magento_Module', BP . '/app/code/Magento/Module']] ], - ['/i18n/', [Context::CONTEXT_TYPE_THEME, 'theme/test.phtml'], []], + [ + BP . '/app/design/frontend/Magento/luma/i18n/', + [Context::CONTEXT_TYPE_THEME, 'frontend/Magento/luma'], + [[ComponentRegistrar::THEME, 'frontend/Magento/luma', BP . '/app/design/frontend/Magento/luma']] + ], + + [ + null, + [Context::CONTEXT_TYPE_MODULE, 'Unregistered_Module'], + [[ComponentRegistrar::MODULE, 'Unregistered_Module', null]] + ], + [ + null, + [Context::CONTEXT_TYPE_THEME, 'frontend/Magento/unregistered'], + [[ComponentRegistrar::THEME, 'frontend/Magento/unregistered', null]] + ], [BP . '/lib/web/i18n/', [Context::CONTEXT_TYPE_LIB, 'lib/web/module/test.phtml'], []], ]; } @@ -138,10 +151,8 @@ public function dataProviderPathToLocaleDirectoryByContext() */ public function testBuildPathToLocaleDirectoryByContextWithInvalidType() { - $this->componentRegistrar->expects($this->any()) - ->method('getPaths') - ->with(ComponentRegistrar::MODULE) - ->willReturn(['module' => '/path/to/module']); + $this->componentRegistrar->expects($this->never()) + ->method('getPath'); $this->context = new Context($this->componentRegistrar); $this->context->buildPathToLocaleDirectoryByContext('invalid_type', 'Magento_Module'); } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/GeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/GeneratorTest.php index 9c182d31f7bae..00c37f1870e78 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/GeneratorTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/GeneratorTest.php @@ -1,6 +1,6 @@ contextMock = $this->getMock(Context::class, [], [], '', false, false); + $this->localeMock = $this->getMock(Locale::class, [], [], '', false, false); + $this->dictionaryMock = $this->getMock(Dictionary::class, [], [], '', false, false); + $this->phraseMock = $this->getMock(Phrase::class, [], [], '', false, false); + $this->factoryMock = $this->getMock(Factory::class, [], [], '', false, false); + + $constructorArguments = $objectManagerHelper->getConstructArguments( + Csv::class, + [ + 'context' => $this->contextMock, + 'factory' => $this->factoryMock + ] + ); + $this->object = $objectManagerHelper->getObject(Csv::class, $constructorArguments); + } + + /** + * @param string $contextType + * @param array $contextValue + * @dataProvider writeDictionaryWithRuntimeExceptionDataProvider + * @expectedException \RuntimeException + * @return void + */ + public function testWriteDictionaryWithRuntimeException($contextType, $contextValue) + { + $this->configureGeneralPhrasesMock($contextType, $contextValue); + + $this->object->writeDictionary($this->dictionaryMock, $this->localeMock); + } + + /** + * @return array + */ + public function writeDictionaryWithRuntimeExceptionDataProvider() + { + return [ + ['', []], + ['module', []], + ['', ['Magento_Module']] + ]; + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Some error. Row #1. + * @return void + */ + public function testWriteDictionaryWithInvalidArgumentException() + { + $contextType = 'module'; + $contextValue = 'Magento_Module'; + + $this->configureGeneralPhrasesMock($contextType, [$contextValue]); + + $this->contextMock->expects($this->once()) + ->method('buildPathToLocaleDirectoryByContext') + ->with($contextType, $contextValue) + ->willThrowException(new \InvalidArgumentException('Some error.')); + + $this->object->writeDictionary($this->dictionaryMock, $this->localeMock); + } + + /** + * @return void + */ + public function testWriteDictionaryWherePathIsNull() + { + $contextType = 'module'; + $contextValue = 'Magento_Module'; + + $this->configureGeneralPhrasesMock($contextType, [$contextValue]); + + $this->contextMock->expects($this->once()) + ->method('buildPathToLocaleDirectoryByContext') + ->with($contextType, $contextValue) + ->willReturn(null); + + $this->phraseMock->expects($this->never()) + ->method('setContextType'); + $this->phraseMock->expects($this->never()) + ->method('setContextValue'); + + $this->object->writeDictionary($this->dictionaryMock, $this->localeMock); + } + + /** + * @return void + */ + public function testWriteDictionary() + { + $contextType = 'module'; + $contextValue = 'Magento_Module'; + $path = '/some/path/'; + $phrase = 'Phrase'; + $locale = 'en_EN'; + $file = $path . $locale . '.' . Csv::FILE_EXTENSION; + + $this->configureGeneralPhrasesMock($contextType, [$contextValue]); + + $this->phraseMock->expects($this->once()) + ->method('getPhrase') + ->willReturn($phrase); + $this->phraseMock->expects($this->once()) + ->method('setContextType') + ->with(null); + $this->phraseMock->expects($this->once()) + ->method('setContextValue') + ->with(null); + $this->localeMock->expects($this->once()) + ->method('__toString') + ->willReturn($locale); + + $this->contextMock->expects($this->once()) + ->method('buildPathToLocaleDirectoryByContext') + ->with($contextType, $contextValue) + ->willReturn($path); + + $writerMock = $this->getMockForAbstractClass(WriterInterface::class); + $writerMock->expects($this->once()) + ->method('write') + ->with($this->phraseMock); + $this->factoryMock->expects($this->once()) + ->method('createDictionaryWriter') + ->with($file) + ->willReturn($writerMock); + + $this->object->writeDictionary($this->dictionaryMock, $this->localeMock); + } + + /** + * @param string $contextType + * @param array $contextValue + * @return void + */ + private function configureGeneralPhrasesMock($contextType, $contextValue) + { + $this->phraseMock->expects($this->any()) + ->method('getContextType') + ->willReturn($contextType); + $this->phraseMock->expects($this->any()) + ->method('getContextValue') + ->willReturn($contextValue); + + $this->dictionaryMock->expects($this->once()) + ->method('getPhrases') + ->willReturn([$this->phraseMock]); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Pack/Writer/File/_files/ioMock.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Pack/Writer/File/_files/ioMock.php new file mode 100644 index 0000000000000..50b9153419b85 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Pack/Writer/File/_files/ioMock.php @@ -0,0 +1,39 @@ + diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/email.html b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/email.html index c25db093ecd33..aa894528348f1 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/email.html +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/email.html @@ -1,6 +1,6 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/file.js b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/file.js index 4b7a3cb8df84a..d835e64d630e8 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/file.js +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/file.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/ParserTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/ParserTest.php index 162264c39514a..bb031cc7f1339 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/ParserTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/ParserTest.php @@ -1,6 +1,6 @@ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/file.js b/setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/file.js index 51ed125d3b1f3..094a9766127a5 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/file.js +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/file.js @@ -1,5 +1,5 @@ /** - * Copyright © 2016 Magento. All rights reserved. + * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ diff --git a/setup/src/Magento/Setup/Test/Unit/Module/ResourceFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/ResourceFactoryTest.php index baf7eb3d01a1a..1bd2b7fda4ca3 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/ResourceFactoryTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/ResourceFactoryTest.php @@ -1,6 +1,6 @@ getMock(\Magento\Framework\App\ResourceConnection::class, [], [], '', false); + $this->resourceModelMock = $this->getMock(ResourceConnection::class, [], [], '', false); $this->connection = $this->getMockForAbstractClass(\Magento\Framework\DB\Adapter\AdapterInterface::class); - $resourceModel->expects($this->any()) + $this->resourceModelMock->expects($this->any()) ->method('getConnection') ->with(self::CONNECTION_NAME) ->will($this->returnValue($this->connection)); - $resourceModel->expects($this->any()) + $this->resourceModelMock->expects($this->any()) ->method('getConnectionByName') - ->with(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION) + ->with(ResourceConnection::DEFAULT_CONNECTION) ->willReturn($this->connection); - $this->setup = new Setup($resourceModel, self::CONNECTION_NAME); + $this->setup = new Setup($this->resourceModelMock, self::CONNECTION_NAME); } public function testGetIdxName() @@ -44,6 +50,11 @@ public function testGetIdxName() $indexType = 'index_type'; $expectedIdxName = 'idxName'; + $this->resourceModelMock->expects($this->once()) + ->method('getTableName') + ->with($tableName) + ->will($this->returnValue($tableName)); + $this->connection->expects($this->once()) ->method('getIndexName') ->with($tableName, $fields, $indexType) @@ -59,6 +70,11 @@ public function testGetFkName() $columnName = 'columnName'; $refColumnName = 'refColumnName'; + $this->resourceModelMock->expects($this->once()) + ->method('getTableName') + ->with($tableName) + ->will($this->returnValue($tableName)); + $this->connection->expects($this->once()) ->method('getForeignKeyName') ->with($tableName, $columnName, $refTable, $refColumnName) diff --git a/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php b/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php index 558533afe9242..0646570b66940 100644 --- a/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Mvc/Bootstrap/InitParamListenerTest.php @@ -1,9 +1,8 @@ withConsecutive( [ \Magento\Framework\App\Filesystem\DirectoryList::class, - $this->isInstanceOf(\Magento\Framework\App\Filesystem\DirectoryList::class) + $this->isInstanceOf(\Magento\Framework\App\Filesystem\DirectoryList::class), ], [ \Magento\Framework\Filesystem::class, - $this->isInstanceOf(\Magento\Framework\Filesystem::class) + $this->isInstanceOf(\Magento\Framework\Filesystem::class), ] ); $mvcApplication->expects($this->any())->method('getServiceManager')->willReturn($serviceManager); @@ -130,10 +129,10 @@ public function testCreateService($zfAppConfig, $env, $cliParam, $expectedArray) $request->expects($this->any()) ->method('getContent') ->willReturn( - $cliParam ? ['install', '--magento-init-params=' . $cliParam ] : ['install'] + $cliParam ? ['install', '--magento-init-params=' . $cliParam] : ['install'] ); $mvcApplication->expects($this->any())->method('getConfig')->willReturn( - $zfAppConfig ? [InitParamListener::BOOTSTRAP_PARAM => $zfAppConfig]:[] + $zfAppConfig ? [InitParamListener::BOOTSTRAP_PARAM => $zfAppConfig] : [] ); $mvcApplication->expects($this->any())->method('getRequest')->willReturn($request); @@ -150,41 +149,55 @@ public function createServiceDataProvider() 'mage_mode App' => [['MAGE_MODE' => 'developer'], [], '', ['MAGE_MODE' => 'developer']], 'mage_mode Env' => [[], ['MAGE_MODE' => 'developer'], '', ['MAGE_MODE' => 'developer']], 'mage_mode CLI' => [[], [], 'MAGE_MODE=developer', ['MAGE_MODE' => 'developer']], - 'one MAGE_DIRS CLI' => [[], [], 'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2', - ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer']], + 'one MAGE_DIRS CLI' => [ + [], + [], + 'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2', + ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer'], + ], 'two MAGE_DIRS CLI' => [ [], [], 'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2&MAGE_DIRS[cache][path]=/tmp/cache', - ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']], - 'MAGE_MODE' => 'developer']], + [ + 'MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']], + 'MAGE_MODE' => 'developer', + ], + ], 'mage_mode only' => [[], [], 'MAGE_MODE=developer', ['MAGE_MODE' => 'developer']], 'MAGE_DIRS Env' => [ [], ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer'], '', - ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer']], + ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2']], 'MAGE_MODE' => 'developer'], + ], 'two MAGE_DIRS' => [ [], [], 'MAGE_MODE=developer&MAGE_DIRS[base][path]=/var/www/magento2&MAGE_DIRS[cache][path]=/tmp/cache', - ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']], - 'MAGE_MODE' => 'developer']], + [ + 'MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2'], 'cache' => ['path' => '/tmp/cache']], + 'MAGE_MODE' => 'developer', + ], + ], 'Env overwrites App' => [ ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/App']], 'MAGE_MODE' => 'developer'], ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']], 'MAGE_MODE' => 'developer'], '', - ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']], 'MAGE_MODE' => 'developer']], + ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']], 'MAGE_MODE' => 'developer'], + ], 'CLI overwrites Env' => [ ['MAGE_MODE' => 'developerApp'], ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']]], 'MAGE_DIRS[base][path]=/var/www/magento2/CLI', - ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'developerApp']], + ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'developerApp'], + ], 'CLI overwrites All' => [ ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/App']], 'MAGE_MODE' => 'production'], ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/Env']]], 'MAGE_DIRS[base][path]=/var/www/magento2/CLI', - ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'production']], + ['MAGE_DIRS' => ['base' => ['path' => '/var/www/magento2/CLI']], 'MAGE_MODE' => 'production'], + ], ]; } @@ -226,6 +239,168 @@ private function prepareEventManager() [$this->listener, 'onBootstrap'] )->willReturn($this->callbackHandler); $eventManager->expects($this->once())->method('getSharedManager')->willReturn($sharedManager); + return $eventManager; } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testAuthPreDispatch() + { + $eventMock = $this->getMockBuilder(\Zend\Mvc\MvcEvent::class) + ->disableOriginalConstructor() + ->getMock(); + $routeMatchMock = $this->getMockBuilder(\Zend\Mvc\Router\Http\RouteMatch::class) + ->disableOriginalConstructor() + ->getMock(); + $applicationMock = $this->getMockBuilder(\Zend\Mvc\Application::class) + ->disableOriginalConstructor() + ->getMock(); + $serviceManagerMock = $this->getMockBuilder(\Zend\ServiceManager\ServiceManager::class) + ->disableOriginalConstructor() + ->getMock(); + $deploymentConfigMock = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $deploymentConfigMock->expects($this->once()) + ->method('isAvailable') + ->willReturn(true); + $omProvider = $this->getMockBuilder(\Magento\Setup\Model\ObjectManagerProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerMock = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class); + $adminAppStateMock = $this->getMockBuilder(\Magento\Framework\App\State::class) + ->disableOriginalConstructor() + ->getMock(); + $sessionConfigMock = $this->getMockBuilder(\Magento\Backend\Model\Session\AdminConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $backendAppListMock = $this->getMockBuilder(\Magento\Backend\App\BackendAppList::class) + ->disableOriginalConstructor() + ->getMock(); + $backendAppMock = $this->getMockBuilder(\Magento\Backend\App\BackendApp::class) + ->disableOriginalConstructor() + ->getMock(); + $backendUrlFactoryMock = $this->getMockBuilder(\Magento\Backend\Model\UrlFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $backendUrlMock = $this->getMockBuilder(\Magento\Backend\Model\Url::class) + ->disableOriginalConstructor() + ->getMock(); + $authenticationMock = $this->getMockBuilder(\Magento\Backend\Model\Auth::class) + ->disableOriginalConstructor() + ->getMock(); + $adminSessionMock = $this->getMockBuilder(\Magento\Backend\Model\Auth\Session::class) + ->disableOriginalConstructor() + ->getMock(); + $responseMock = $this->getMockBuilder(\Zend\Http\Response::class) + ->disableOriginalConstructor() + ->getMock(); + $headersMock = $this->getMockBuilder(\Zend\Http\Headers::class) + ->disableOriginalConstructor() + ->getMock(); + + $routeMatchMock->expects($this->once()) + ->method('getParam') + ->with('controller') + ->willReturn('testController'); + $eventMock->expects($this->once()) + ->method('getRouteMatch') + ->willReturn($routeMatchMock); + $eventMock->expects($this->once()) + ->method('getApplication') + ->willReturn($applicationMock); + $serviceManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap( + [ + [ + \Magento\Framework\App\DeploymentConfig::class, + true, + $deploymentConfigMock, + ], + [ + \Magento\Setup\Model\ObjectManagerProvider::class, + true, + $omProvider, + ], + ] + ); + $objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap( + [ + [ + \Magento\Framework\App\State::class, + $adminAppStateMock, + ], + [ + \Magento\Backend\Model\Session\AdminConfig::class, + $sessionConfigMock, + ], + [ + \Magento\Backend\App\BackendAppList::class, + $backendAppListMock, + ], + [ + \Magento\Backend\Model\UrlFactory::class, + $backendUrlFactoryMock, + ], + [ + \Magento\Backend\Model\Auth::class, + $authenticationMock, + ], + ] + ); + $objectManagerMock->expects($this->any()) + ->method('create') + ->willReturn($adminSessionMock); + $omProvider->expects($this->once()) + ->method('get') + ->willReturn($objectManagerMock); + $adminAppStateMock->expects($this->once()) + ->method('setAreaCode') + ->with(\Magento\Framework\App\Area::AREA_ADMINHTML); + $applicationMock->expects($this->once()) + ->method('getServiceManager') + ->willReturn($serviceManagerMock); + $backendAppMock->expects($this->once()) + ->method('getCookiePath') + ->willReturn(''); + $backendUrlFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($backendUrlMock); + $backendAppListMock->expects($this->once()) + ->method('getBackendApp') + ->willReturn($backendAppMock); + $authenticationMock->expects($this->once()) + ->method('isLoggedIn') + ->willReturn(true); + $adminSessionMock->expects($this->once()) + ->method('isAllowed') + ->with('Magento_Backend::setup_wizard', null) + ->willReturn(false); + $adminSessionMock->expects($this->once()) + ->method('destroy'); + $eventMock->expects($this->once()) + ->method('getResponse') + ->willReturn($responseMock); + $responseMock->expects($this->once()) + ->method('getHeaders') + ->willReturn($headersMock); + $headersMock->expects($this->once()) + ->method('addHeaderLine'); + $responseMock->expects($this->once()) + ->method('setStatusCode') + ->with(302); + $eventMock->expects($this->once()) + ->method('stopPropagation'); + + $this->assertSame( + $this->listener->authPreDispatch($eventMock), + $responseMock + ); + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Validator/DbValidatorTest.php b/setup/src/Magento/Setup/Test/Unit/Validator/DbValidatorTest.php index c263531979573..b04b173e652b9 100644 --- a/setup/src/Magento/Setup/Test/Unit/Validator/DbValidatorTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Validator/DbValidatorTest.php @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/add-database.phtml b/setup/view/magento/setup/add-database.phtml index 6d25db2e08444..3771a66447381 100644 --- a/setup/view/magento/setup/add-database.phtml +++ b/setup/view/magento/setup/add-database.phtml @@ -1,6 +1,6 @@
    -
    \ No newline at end of file +
    diff --git a/setup/view/magento/setup/customize-your-store.phtml b/setup/view/magento/setup/customize-your-store.phtml index e16362721dfde..9cfab20171a0e 100644 --- a/setup/view/magento/setup/customize-your-store.phtml +++ b/setup/view/magento/setup/customize-your-store.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/extension-grid.phtml b/setup/view/magento/setup/extension-grid.phtml index 1096adca72043..45508cfe186ff 100644 --- a/setup/view/magento/setup/extension-grid.phtml +++ b/setup/view/magento/setup/extension-grid.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/home.phtml b/setup/view/magento/setup/home.phtml index f5783f07e0a4a..bd0151f23d69c 100644 --- a/setup/view/magento/setup/home.phtml +++ b/setup/view/magento/setup/home.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/index.phtml b/setup/view/magento/setup/index.phtml index ba9096c5766c6..81e39cb64fd0a 100644 --- a/setup/view/magento/setup/index.phtml +++ b/setup/view/magento/setup/index.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/install-extension-grid.phtml b/setup/view/magento/setup/install-extension-grid.phtml index e2bcbf9a777c8..3cb59b01f9d9c 100644 --- a/setup/view/magento/setup/install-extension-grid.phtml +++ b/setup/view/magento/setup/install-extension-grid.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/install.phtml b/setup/view/magento/setup/install.phtml index 06eb1a082ca66..01785701b0ed5 100644 --- a/setup/view/magento/setup/install.phtml +++ b/setup/view/magento/setup/install.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/marketplace-credentials.phtml b/setup/view/magento/setup/marketplace-credentials.phtml index f5357c781d191..8b7a11c030ec7 100644 --- a/setup/view/magento/setup/marketplace-credentials.phtml +++ b/setup/view/magento/setup/marketplace-credentials.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/module-grid.phtml b/setup/view/magento/setup/module-grid.phtml index 3f4f755ae3f6d..5576f823f1d10 100644 --- a/setup/view/magento/setup/module-grid.phtml +++ b/setup/view/magento/setup/module-grid.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/navigation/header-bar.phtml b/setup/view/magento/setup/navigation/header-bar.phtml index 540bfcfed6359..698ac25346f43 100644 --- a/setup/view/magento/setup/navigation/header-bar.phtml +++ b/setup/view/magento/setup/navigation/header-bar.phtml @@ -1,6 +1,6 @@
    - \ No newline at end of file + diff --git a/setup/view/magento/setup/navigation/menu.phtml b/setup/view/magento/setup/navigation/menu.phtml index ae94a891255dc..b7e5052e4231d 100644 --- a/setup/view/magento/setup/navigation/menu.phtml +++ b/setup/view/magento/setup/navigation/menu.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/readiness-check.phtml b/setup/view/magento/setup/readiness-check.phtml index 2aaf4de649bf0..018e3274f0167 100644 --- a/setup/view/magento/setup/readiness-check.phtml +++ b/setup/view/magento/setup/readiness-check.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/readiness-check/progress.phtml b/setup/view/magento/setup/readiness-check/progress.phtml index 6719d825dfcde..c2d21b911cbee 100755 --- a/setup/view/magento/setup/readiness-check/progress.phtml +++ b/setup/view/magento/setup/readiness-check/progress.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/start-updater.phtml b/setup/view/magento/setup/start-updater.phtml index fd31f994c3923..c4d226ceaab0b 100644 --- a/setup/view/magento/setup/start-updater.phtml +++ b/setup/view/magento/setup/start-updater.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/success.phtml b/setup/view/magento/setup/success.phtml index c220d91e7d058..7931bc670177e 100644 --- a/setup/view/magento/setup/success.phtml +++ b/setup/view/magento/setup/success.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/update-extension-grid.phtml b/setup/view/magento/setup/update-extension-grid.phtml index 62c9b1217f2a5..e26df4d90a2c8 100644 --- a/setup/view/magento/setup/update-extension-grid.phtml +++ b/setup/view/magento/setup/update-extension-grid.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/updater-success.phtml b/setup/view/magento/setup/updater-success.phtml index 07855edcaafc7..da91d44ef1efd 100644 --- a/setup/view/magento/setup/updater-success.phtml +++ b/setup/view/magento/setup/updater-success.phtml @@ -1,6 +1,6 @@ diff --git a/setup/view/magento/setup/web-configuration.phtml b/setup/view/magento/setup/web-configuration.phtml index d2097f78527b5..2fbc5f20d21d6 100644 --- a/setup/view/magento/setup/web-configuration.phtml +++ b/setup/view/magento/setup/web-configuration.phtml @@ -1,6 +1,6 @@
    - +
    @@ -40,6 +40,13 @@ $hints = [

    {{$state.current.header}}

    +
    + {{validateUrl.failed}} +
    +
    - + Please enter a valid base URL path. (ex: http://www.example.com/)
    @@ -189,10 +200,16 @@ $hints = [ ng-class="{'invalid': webconfig.https.$invalid && webconfig.submitted}" ng-if="config.https.front || config.https.admin" ng-focus="" + ng-pattern="/^(https?:\/\/).*$/" required >
    - Please enter a valid HTTPS base URL path. (ex: https://www.example.com/) + + Please enter a valid HTTPS base URL path. (ex: https://www.example.com/) +
    diff --git a/setup/view/styles/lib/variables/_buttons.less b/setup/view/styles/lib/variables/_buttons.less index bca8f0b99ee0b..4195c9f5e1f01 100644 --- a/setup/view/styles/lib/variables/_buttons.less +++ b/setup/view/styles/lib/variables/_buttons.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/setup/view/styles/lib/variables/_colors.less b/setup/view/styles/lib/variables/_colors.less index d6ace229c3b2c..7c190258c6907 100644 --- a/setup/view/styles/lib/variables/_colors.less +++ b/setup/view/styles/lib/variables/_colors.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */ diff --git a/setup/view/styles/lib/variables/_typography.less b/setup/view/styles/lib/variables/_typography.less index 7593038ef3659..bff801ad14786 100644 --- a/setup/view/styles/lib/variables/_typography.less +++ b/setup/view/styles/lib/variables/_typography.less @@ -1,5 +1,5 @@ // /** -// * Copyright © 2016 Magento. All rights reserved. +// * Copyright © 2013-2017 Magento, Inc. All rights reserved. // * See COPYING.txt for license details. // */